19 package org.sleuthkit.autopsy.centralrepository.datamodel;
 
   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;
 
   40 import java.util.Optional;
 
   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;
 
   54 import org.
sleuthkit.datamodel.CaseDbSchemaVersionNumber;
 
   56 import org.
sleuthkit.datamodel.InvalidAccountIDException;
 
   65 abstract class RdbmsCentralRepo 
implements CentralRepository {
 
   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);
 
   74     protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
 
   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).
 
   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).
 
   92     private static final Cache<Integer, CorrelationCase> caseCacheById = CacheBuilder.newBuilder()
 
   93             .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
 
   95     private static final Cache<String, CorrelationDataSource> dataSourceCacheByDsObjectId = CacheBuilder.newBuilder()
 
   96             .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
 
   98     private static final Cache<String, CorrelationDataSource> dataSourceCacheById = CacheBuilder.newBuilder()
 
   99             .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
 
  102     static final int MAX_VALUE_LENGTH = 256;
 
  106     static final int DEFAULT_BULK_THRESHHOLD = 1000;
 
  108     private static final int QUERY_STR_MAX_LEN = 1000;
 
  115     protected RdbmsCentralRepo() throws CentralRepoException {
 
  116         isCRTypeCacheInitialized = 
false;
 
  117         bulkArtifactsCount = 0;
 
  118         bulkArtifacts = 
new HashMap<>();
 
  120         defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
 
  121         defaultCorrelationTypes.forEach((type) -> {
 
  122             bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(type), 
new ArrayList<>());
 
  129     protected abstract Connection connect(
boolean foreignKeys) 
throws CentralRepoException;
 
  134     protected abstract Connection connect() throws CentralRepoException;
 
  139     protected abstract Connection getEphemeralConnection();
 
  150     public 
void newDbInfo(String name, String value) throws CentralRepoException {
 
  151         Connection conn = connect();
 
  153         PreparedStatement preparedStatement = null;
 
  154         String sql = 
"INSERT INTO db_info (name, value) VALUES (?, ?) " 
  155                 + getConflictClause();
 
  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);
 
  164             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  165             CentralRepoDbUtil.closeConnection(conn);
 
  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=?";
 
  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);
 
  183             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  184             CentralRepoDbUtil.closeConnection(conn);
 
  198     public String getDbInfo(String name) 
throws CentralRepoException {
 
  199         Connection conn = connect();
 
  201         PreparedStatement preparedStatement = null;
 
  202         ResultSet resultSet = null;
 
  204         String sql = 
"SELECT value FROM db_info WHERE name=?";
 
  206             preparedStatement = conn.prepareStatement(sql);
 
  207             preparedStatement.setString(1, name);
 
  208             resultSet = preparedStatement.executeQuery();
 
  209             if (resultSet.next()) {
 
  210                 value = resultSet.getString(
"value");
 
  212         } 
catch (SQLException ex) {
 
  213             throw new CentralRepoException(
"Error getting value for name.", ex);
 
  215             CentralRepoDbUtil.closeResultSet(resultSet);
 
  216             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  217             CentralRepoDbUtil.closeConnection(conn);
 
  226     public final void clearCaches() {
 
  227         synchronized (typeCache) {
 
  228             typeCache.invalidateAll();
 
  229             isCRTypeCacheInitialized = 
false;
 
  231         caseCacheByUUID.invalidateAll();
 
  232         caseCacheById.invalidateAll();
 
  233         dataSourceCacheByDsObjectId.invalidateAll();
 
  234         dataSourceCacheById.invalidateAll();
 
  235         accountsCache.invalidateAll();
 
  247     public void updateDbInfo(String name, String value) 
throws CentralRepoException {
 
  248         Connection conn = connect();
 
  250         PreparedStatement preparedStatement = null;
 
  251         String sql = 
"UPDATE db_info SET value=? WHERE name=?";
 
  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);
 
  260             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  261             CentralRepoDbUtil.closeConnection(conn);
 
  275     public synchronized CorrelationCase newCase(CorrelationCase eamCase) 
throws CentralRepoException {
 
  277         if (eamCase.getCaseUUID() == null) {
 
  278             throw new CentralRepoException(
"Case UUID is null");
 
  282         CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
 
  283         if (cRCase != null) {
 
  287         Connection conn = connect();
 
  288         PreparedStatement preparedStatement = null;
 
  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;
 
  296             preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
 
  298             preparedStatement.setString(1, eamCase.getCaseUUID());
 
  299             if (null == eamCase.getOrg()) {
 
  300                 preparedStatement.setNull(2, Types.INTEGER);
 
  302                 preparedStatement.setInt(2, eamCase.getOrg().getOrgID());
 
  304             preparedStatement.setString(3, eamCase.getDisplayName());
 
  305             preparedStatement.setString(4, eamCase.getCreationDate());
 
  306             if (
"".equals(eamCase.getCaseNumber())) {
 
  307                 preparedStatement.setNull(5, Types.INTEGER);
 
  309                 preparedStatement.setString(5, eamCase.getCaseNumber());
 
  311             if (
"".equals(eamCase.getExaminerName())) {
 
  312                 preparedStatement.setNull(6, Types.INTEGER);
 
  314                 preparedStatement.setString(6, eamCase.getExaminerName());
 
  316             if (
"".equals(eamCase.getExaminerEmail())) {
 
  317                 preparedStatement.setNull(7, Types.INTEGER);
 
  319                 preparedStatement.setString(7, eamCase.getExaminerEmail());
 
  321             if (
"".equals(eamCase.getExaminerPhone())) {
 
  322                 preparedStatement.setNull(8, Types.INTEGER);
 
  324                 preparedStatement.setString(8, eamCase.getExaminerPhone());
 
  326             if (
"".equals(eamCase.getNotes())) {
 
  327                 preparedStatement.setNull(9, Types.INTEGER);
 
  329                 preparedStatement.setString(9, eamCase.getNotes());
 
  332             preparedStatement.executeUpdate();
 
  334             resultSet = preparedStatement.getGeneratedKeys();
 
  335             if (!resultSet.next()) {
 
  336                 throw new CentralRepoException(String.format(
"Failed to INSERT case %s in central repo", eamCase.getCaseUUID()));
 
  338             int caseID = resultSet.getInt(1); 
 
  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); 
 
  347             CentralRepoDbUtil.closeResultSet(resultSet);
 
  348             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  349             CentralRepoDbUtil.closeConnection(conn);
 
  353         return getCaseByUUID(eamCase.getCaseUUID());
 
  362     public CorrelationCase newCase(Case autopsyCase) 
throws CentralRepoException {
 
  363         if (autopsyCase == null) {
 
  364             throw new CentralRepoException(
"Case is null");
 
  367         CorrelationCase curCeCase = 
new CorrelationCase(
 
  369                 autopsyCase.getName(), 
 
  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);
 
  382     public CorrelationCase getCase(Case autopsyCase) 
throws CentralRepoException {
 
  383         return getCaseByUUID(autopsyCase.getName());
 
  392     public void updateCase(CorrelationCase eamCase) 
throws CentralRepoException {
 
  393         if (eamCase == null) {
 
  394             throw new CentralRepoException(
"Correlation case is null");
 
  397         Connection conn = connect();
 
  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=?";
 
  405             preparedStatement = conn.prepareStatement(sql);
 
  407             if (null == eamCase.getOrg()) {
 
  408                 preparedStatement.setNull(1, Types.INTEGER);
 
  410                 preparedStatement.setInt(1, eamCase.getOrg().getOrgID());
 
  412             preparedStatement.setString(2, eamCase.getDisplayName());
 
  413             preparedStatement.setString(3, eamCase.getCreationDate());
 
  415             if (
"".equals(eamCase.getCaseNumber())) {
 
  416                 preparedStatement.setNull(4, Types.INTEGER);
 
  418                 preparedStatement.setString(4, eamCase.getCaseNumber());
 
  420             if (
"".equals(eamCase.getExaminerName())) {
 
  421                 preparedStatement.setNull(5, Types.INTEGER);
 
  423                 preparedStatement.setString(5, eamCase.getExaminerName());
 
  425             if (
"".equals(eamCase.getExaminerEmail())) {
 
  426                 preparedStatement.setNull(6, Types.INTEGER);
 
  428                 preparedStatement.setString(6, eamCase.getExaminerEmail());
 
  430             if (
"".equals(eamCase.getExaminerPhone())) {
 
  431                 preparedStatement.setNull(7, Types.INTEGER);
 
  433                 preparedStatement.setString(7, eamCase.getExaminerPhone());
 
  435             if (
"".equals(eamCase.getNotes())) {
 
  436                 preparedStatement.setNull(8, Types.INTEGER);
 
  438                 preparedStatement.setString(8, eamCase.getNotes());
 
  441             preparedStatement.setString(9, eamCase.getCaseUUID());
 
  443             preparedStatement.executeUpdate();
 
  445             caseCacheById.put(eamCase.getID(), eamCase);
 
  446             caseCacheByUUID.put(eamCase.getCaseUUID(), eamCase);
 
  447         } 
catch (SQLException ex) {
 
  448             throw new CentralRepoException(
"Error updating case.", ex); 
 
  450             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  451             CentralRepoDbUtil.closeConnection(conn);
 
  463     public CorrelationCase getCaseByUUID(String caseUUID) 
throws CentralRepoException {
 
  465             return caseCacheByUUID.get(caseUUID, () -> getCaseByUUIDFromCr(caseUUID));
 
  466         } 
catch (CacheLoader.InvalidCacheLoadException ignored) {
 
  469         } 
catch (ExecutionException ex) {
 
  470             throw new CentralRepoException(
"Error getting autopsy case from Central repo", ex);
 
  481     private CorrelationCase getCaseByUUIDFromCr(String caseUUID) 
throws CentralRepoException {
 
  482         Connection conn = connect();
 
  484         CorrelationCase eamCaseResult = null;
 
  485         PreparedStatement preparedStatement = null;
 
  486         ResultSet resultSet = null;
 
  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 " 
  491                 + 
"LEFT JOIN organizations ON cases.org_id=organizations.id " 
  492                 + 
"WHERE case_uid=?";
 
  495             preparedStatement = conn.prepareStatement(sql);
 
  496             preparedStatement.setString(1, caseUUID);
 
  497             resultSet = preparedStatement.executeQuery();
 
  498             if (resultSet.next()) {
 
  499                 eamCaseResult = getEamCaseFromResultSet(resultSet);
 
  501             if (eamCaseResult != null) {
 
  503                 caseCacheById.put(eamCaseResult.getID(), eamCaseResult);
 
  505         } 
catch (SQLException ex) {
 
  506             throw new CentralRepoException(
"Error getting case details.", ex); 
 
  508             CentralRepoDbUtil.closeResultSet(resultSet);
 
  509             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  510             CentralRepoDbUtil.closeConnection(conn);
 
  513         return eamCaseResult;
 
  524     public CorrelationCase getCaseById(
int caseId) 
throws CentralRepoException {
 
  526             return caseCacheById.get(caseId, () -> getCaseByIdFromCr(caseId));
 
  527         } 
catch (CacheLoader.InvalidCacheLoadException ignored) {
 
  530         } 
catch (ExecutionException ex) {
 
  531             throw new CentralRepoException(
"Error getting autopsy case from Central repo", ex);
 
  542     private CorrelationCase getCaseByIdFromCr(
int caseId) 
throws CentralRepoException {
 
  543         Connection conn = connect();
 
  545         CorrelationCase eamCaseResult = null;
 
  546         PreparedStatement preparedStatement = null;
 
  547         ResultSet resultSet = null;
 
  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 " 
  552                 + 
"LEFT JOIN organizations ON cases.org_id=organizations.id " 
  553                 + 
"WHERE cases.id=?";
 
  555             preparedStatement = conn.prepareStatement(sql);
 
  556             preparedStatement.setInt(1, caseId);
 
  557             resultSet = preparedStatement.executeQuery();
 
  558             if (resultSet.next()) {
 
  559                 eamCaseResult = getEamCaseFromResultSet(resultSet);
 
  561             if (eamCaseResult != null) {
 
  563                 caseCacheByUUID.put(eamCaseResult.getCaseUUID(), eamCaseResult);
 
  565         } 
catch (SQLException ex) {
 
  566             throw new CentralRepoException(
"Error getting case details.", ex); 
 
  568             CentralRepoDbUtil.closeResultSet(resultSet);
 
  569             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  570             CentralRepoDbUtil.closeConnection(conn);
 
  573         return eamCaseResult;
 
  582     public List<CorrelationCase> getCases() throws CentralRepoException {
 
  583         Connection conn = connect();
 
  585         List<CorrelationCase> cases = 
new ArrayList<>();
 
  586         CorrelationCase eamCaseResult;
 
  587         PreparedStatement preparedStatement = null;
 
  588         ResultSet resultSet = null;
 
  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 " 
  593                 + 
"LEFT JOIN organizations ON cases.org_id=organizations.id";
 
  596             preparedStatement = conn.prepareStatement(sql);
 
  597             resultSet = preparedStatement.executeQuery();
 
  598             while (resultSet.next()) {
 
  599                 eamCaseResult = getEamCaseFromResultSet(resultSet);
 
  600                 cases.add(eamCaseResult);
 
  602         } 
catch (SQLException ex) {
 
  603             throw new CentralRepoException(
"Error getting all cases.", ex); 
 
  605             CentralRepoDbUtil.closeResultSet(resultSet);
 
  606             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  607             CentralRepoDbUtil.closeConnection(conn);
 
  623     private static String getDataSourceByDSObjectIdCacheKey(
int caseId, Long dataSourceObjectId) {
 
  624         return "Case" + caseId + 
"DsObjectId" + dataSourceObjectId; 
 
  636     private static String getDataSourceByIdCacheKey(
int caseId, 
int dataSourceId) {
 
  637         return "Case" + caseId + 
"Id" + dataSourceId; 
 
  646     public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) 
throws CentralRepoException {
 
  647         if (eamDataSource.getCaseID() == -1) {
 
  648             throw new CentralRepoException(
"Case ID is -1");
 
  650         if (eamDataSource.getDeviceID() == null) {
 
  651             throw new CentralRepoException(
"Device ID is null");
 
  653         if (eamDataSource.getName() == null) {
 
  654             throw new CentralRepoException(
"Name is null");
 
  656         if (eamDataSource.getID() != -1) {
 
  658             return eamDataSource;
 
  661         Connection conn = connect();
 
  663         PreparedStatement preparedStatement = null;
 
  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;
 
  669             preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
 
  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());
 
  679             preparedStatement.executeUpdate();
 
  680             resultSet = preparedStatement.getGeneratedKeys();
 
  681             if (!resultSet.next()) {
 
  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);
 
  698                 int dataSourceId = resultSet.getInt(1); 
 
  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);
 
  705         } 
catch (SQLException insertException) {
 
  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);
 
  722             CentralRepoDbUtil.closeResultSet(resultSet);
 
  723             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  724             CentralRepoDbUtil.closeConnection(conn);
 
  740     public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long dataSourceObjectId) 
throws CentralRepoException {
 
  742         if (correlationCase == null) {
 
  743             throw new CentralRepoException(
"Correlation case is null");
 
  746             return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), dataSourceObjectId), () -> getDataSourceFromCr(correlationCase.getID(), dataSourceObjectId));
 
  747         } 
catch (CacheLoader.InvalidCacheLoadException ignored) {
 
  750         } 
catch (ExecutionException ex) {
 
  751             throw new CentralRepoException(
"Error getting data source from central repository", ex);
 
  767     private CorrelationDataSource getDataSourceFromCr(
int correlationCaseId, Long dataSourceObjectId) 
throws CentralRepoException {
 
  768         Connection conn = connect();
 
  770         CorrelationDataSource eamDataSourceResult = null;
 
  771         PreparedStatement preparedStatement = null;
 
  772         ResultSet resultSet = null;
 
  774         String sql = 
"SELECT * FROM data_sources WHERE datasource_obj_id=? AND case_id=?"; 
 
  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);
 
  784             if (eamDataSourceResult != null) {
 
  785                 dataSourceCacheById.put(getDataSourceByIdCacheKey(correlationCaseId, eamDataSourceResult.getID()), eamDataSourceResult);
 
  787         } 
catch (SQLException ex) {
 
  788             throw new CentralRepoException(
"Error getting data source.", ex); 
 
  790             CentralRepoDbUtil.closeResultSet(resultSet);
 
  791             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  792             CentralRepoDbUtil.closeConnection(conn);
 
  795         return eamDataSourceResult;
 
  808     public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, 
int dataSourceId) 
throws CentralRepoException {
 
  809         if (correlationCase == null) {
 
  810             throw new CentralRepoException(
"Correlation case is null");
 
  813             return dataSourceCacheById.get(getDataSourceByIdCacheKey(correlationCase.getID(), dataSourceId), () -> getDataSourceByIdFromCr(correlationCase, dataSourceId));
 
  814         } 
catch (CacheLoader.InvalidCacheLoadException ignored) {
 
  817         } 
catch (ExecutionException ex) {
 
  818             throw new CentralRepoException(
"Error getting data source from central repository", ex);
 
  831     private CorrelationDataSource getDataSourceByIdFromCr(CorrelationCase correlationCase, 
int dataSourceId) 
throws CentralRepoException {
 
  832         Connection conn = connect();
 
  834         CorrelationDataSource eamDataSourceResult = null;
 
  835         PreparedStatement preparedStatement = null;
 
  836         ResultSet resultSet = null;
 
  838         String sql = 
"SELECT * FROM data_sources WHERE id=? AND case_id=?"; 
 
  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);
 
  848             if (eamDataSourceResult != null) {
 
  849                 dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDataSourceObjectID()), eamDataSourceResult);
 
  851         } 
catch (SQLException ex) {
 
  852             throw new CentralRepoException(
"Error getting data source.", ex); 
 
  854             CentralRepoDbUtil.closeResultSet(resultSet);
 
  855             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  856             CentralRepoDbUtil.closeConnection(conn);
 
  859         return eamDataSourceResult;
 
  868     public List<CorrelationDataSource> getDataSources() throws CentralRepoException {
 
  869         Connection conn = connect();
 
  871         List<CorrelationDataSource> dataSources = 
new ArrayList<>();
 
  872         CorrelationDataSource eamDataSourceResult;
 
  873         PreparedStatement preparedStatement = null;
 
  874         ResultSet resultSet = null;
 
  876         String sql = 
"SELECT * FROM data_sources";
 
  879             preparedStatement = conn.prepareStatement(sql);
 
  880             resultSet = preparedStatement.executeQuery();
 
  881             while (resultSet.next()) {
 
  882                 eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
 
  883                 dataSources.add(eamDataSourceResult);
 
  885         } 
catch (SQLException ex) {
 
  886             throw new CentralRepoException(
"Error getting all data sources.", ex); 
 
  888             CentralRepoDbUtil.closeResultSet(resultSet);
 
  889             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  890             CentralRepoDbUtil.closeConnection(conn);
 
  902     public void updateDataSourceMd5Hash(CorrelationDataSource eamDataSource) 
throws CentralRepoException {
 
  903         updateDataSourceStringValue(eamDataSource, 
"md5", eamDataSource.getMd5());
 
  912     public void updateDataSourceSha1Hash(CorrelationDataSource eamDataSource) 
throws CentralRepoException {
 
  913         updateDataSourceStringValue(eamDataSource, 
"sha1", eamDataSource.getSha1());
 
  923     public void updateDataSourceSha256Hash(CorrelationDataSource eamDataSource) 
throws CentralRepoException {
 
  924         updateDataSourceStringValue(eamDataSource, 
"sha256", eamDataSource.getSha256());
 
  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");
 
  939         Connection conn = connect();
 
  941         PreparedStatement preparedStatement = null;
 
  942         String sql = 
"UPDATE data_sources " 
  943                 + 
"SET " + column + 
"=? " 
  947             preparedStatement = conn.prepareStatement(sql);
 
  949             preparedStatement.setString(1, value);
 
  950             preparedStatement.setInt(2, eamDataSource.getID());
 
  952             preparedStatement.executeUpdate();
 
  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); 
 
  959             CentralRepoDbUtil.closeStatement(preparedStatement);
 
  960             CentralRepoDbUtil.closeConnection(conn);
 
  973     public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) 
throws CentralRepoException {
 
  975         Connection conn = connect();
 
  977         PreparedStatement preparedStatement = null;
 
  979         String sql = 
"UPDATE data_sources SET name = ? WHERE id = ?";
 
  982             preparedStatement = conn.prepareStatement(sql);
 
  983             preparedStatement.setString(1, newName);
 
  984             preparedStatement.setInt(2, eamDataSource.getID());
 
  985             preparedStatement.executeUpdate();
 
  987             CorrelationDataSource updatedDataSource = 
new CorrelationDataSource(
 
  988                     eamDataSource.getCaseID(),
 
  989                     eamDataSource.getID(),
 
  990                     eamDataSource.getDeviceID(),
 
  992                     eamDataSource.getDataSourceObjectID(),
 
  993                     eamDataSource.getMd5(),
 
  994                     eamDataSource.getSha1(),
 
  995                     eamDataSource.getSha256());
 
  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); 
 
 1003             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1004             CentralRepoDbUtil.closeConnection(conn);
 
 1015     public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) 
throws CentralRepoException {
 
 1016         checkAddArtifactInstanceNulls(eamArtifact);
 
 1019         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
 
 1020         boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType());
 
 1024         if (artifactHasAnAccount) {
 
 1025             sql = 
"INSERT INTO " 
 1027                     + 
"(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) " 
 1028                     + 
"VALUES (?, ?, ?, ?, ?, ?, ?, ?) " 
 1029                     + getConflictClause();
 
 1031             sql = 
"INSERT INTO " 
 1033                     + 
"(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) " 
 1034                     + 
"VALUES (?, ?, ?, ?, ?, ?, ?) " 
 1035                     + getConflictClause();
 
 1038         try (Connection conn = connect();
 
 1039                 PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
 
 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());
 
 1048                 if (
"".equals(eamArtifact.getComment())) {
 
 1049                     preparedStatement.setNull(6, Types.INTEGER);
 
 1051                     preparedStatement.setString(6, eamArtifact.getComment());
 
 1053                 preparedStatement.setLong(7, eamArtifact.getFileObjectId());
 
 1056                 if (artifactHasAnAccount) {
 
 1057                     if (eamArtifact.getAccountId() >= 0) {
 
 1058                         preparedStatement.setLong(8, eamArtifact.getAccountId());
 
 1060                         preparedStatement.setNull(8, Types.INTEGER);
 
 1064                 preparedStatement.executeUpdate();
 
 1067         } 
catch (SQLException ex) {
 
 1068             throw new CentralRepoException(
"Error inserting new artifact into artifacts table.", ex); 
 
 1085     public CentralRepoAccount 
getOrCreateAccount(CentralRepoAccountType crAccountType, String accountUniqueID) 
throws InvalidAccountIDException, CentralRepoException {
 
 1087         String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
 
 1091         switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
 
 1093                 insertSQL = 
"INSERT INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) " + getConflictClause();  
 
 1096                 insertSQL = 
"INSERT OR IGNORE INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) "; 
 
 1099                 throw new CentralRepoException(String.format(
"Cannot add account to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); 
 
 1102         try (Connection connection = connect();
 
 1103                 PreparedStatement preparedStatement = connection.prepareStatement(insertSQL);) {
 
 1105             preparedStatement.setInt(1, crAccountType.getAccountTypeId());
 
 1106             preparedStatement.setString(2, normalizedAccountID);
 
 1108             preparedStatement.executeUpdate();
 
 1111             return getAccount(crAccountType, normalizedAccountID);
 
 1112         } 
catch (SQLException ex) {
 
 1113             throw new CentralRepoException(
"Error adding an account to CR database.", ex);
 
 1118     public Optional<CentralRepoAccountType> getAccountTypeByName(String accountTypeName) 
throws CentralRepoException {
 
 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);
 
 1127     public Collection<CentralRepoAccountType> getAllAccountTypes() throws CentralRepoException {
 
 1129         Collection<CentralRepoAccountType> accountTypes = 
new ArrayList<>();
 
 1131         String sql = 
"SELECT * FROM account_types";
 
 1132         try (Connection conn = connect();
 
 1133                 PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
 
 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"));
 
 1140                     accountTypes.add(crAccountType);
 
 1143         } 
catch (SQLException ex) {
 
 1144             throw new CentralRepoException(
"Error getting account types from central repository.", ex); 
 
 1146         return accountTypes;
 
 1158     private Optional<CentralRepoAccountType> getCRAccountTypeFromDb(String accountTypeName) 
throws CentralRepoException {
 
 1160         String sql = 
"SELECT * FROM account_types WHERE type_name = ?";
 
 1161         try (Connection conn = connect();
 
 1162                 PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
 
 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);
 
 1172                     accountTypesCache.put(accountTypeName, Optional.empty());
 
 1173                     return Optional.empty();
 
 1176         } 
catch (SQLException ex) {
 
 1177             throw new CentralRepoException(
"Error getting correlation type by id.", ex); 
 
 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);
 
 1225     private CentralRepoAccount getCRAccountFromDb(CentralRepoAccountType crAccountType, String accountUniqueID) 
throws CentralRepoException {
 
 1227         CentralRepoAccount account = null;
 
 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);) {
 
 1233             preparedStatement.setInt(1, crAccountType.getAccountTypeId());
 
 1234             preparedStatement.setString(2, accountUniqueID);
 
 1236             try (ResultSet resultSet = preparedStatement.executeQuery();) {
 
 1237                 if (resultSet.next()) {
 
 1238                     account = 
new CentralRepoAccount(resultSet.getInt(
"id"), crAccountType, resultSet.getString(
"account_unique_identifier"));   
 
 1241         } 
catch (SQLException ex) {
 
 1242             throw new CentralRepoException(
"Error getting account type id", ex);
 
 1248     private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) 
throws CentralRepoException {
 
 1249         if (eamArtifact == null) {
 
 1250             throw new CentralRepoException(
"CorrelationAttribute is null");
 
 1252         if (eamArtifact.getCorrelationType() == null) {
 
 1253             throw new CentralRepoException(
"Correlation type is null");
 
 1255         if (eamArtifact.getCorrelationValue() == null) {
 
 1256             throw new CentralRepoException(
"Correlation value is null");
 
 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());
 
 1265         if (eamArtifact.getCorrelationCase() == null) {
 
 1266             throw new CentralRepoException(
"CorrelationAttributeInstance case is null");
 
 1268         if (eamArtifact.getCorrelationDataSource() == null) {
 
 1269             throw new CentralRepoException(
"CorrelationAttributeInstance data source is null");
 
 1271         if (eamArtifact.getKnownStatus() == null) {
 
 1272             throw new CentralRepoException(
"CorrelationAttributeInstance known status is null");
 
 1277     public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1278         if (value == null) {
 
 1279             throw new CorrelationAttributeNormalizationException(
"Cannot get artifact instances for null value");
 
 1281         return getArtifactInstancesByTypeValues(aType, Arrays.asList(value));
 
 1285     public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1286         if (aType == null) {
 
 1287             throw new CorrelationAttributeNormalizationException(
"Cannot get artifact instances for null type");
 
 1289         if (values == null || values.isEmpty()) {
 
 1290             throw new CorrelationAttributeNormalizationException(
"Cannot get artifact instances without specified values");
 
 1292         return getArtifactInstances(prepareGetInstancesSql(aType, values), aType);
 
 1296     public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1297         if (aType == null) {
 
 1298             throw new CorrelationAttributeNormalizationException(
"Cannot get artifact instances for null type");
 
 1300         if (values == null || values.isEmpty()) {
 
 1301             throw new CorrelationAttributeNormalizationException(
"Cannot get artifact instances without specified values");
 
 1303         if (caseIds == null || caseIds.isEmpty()) {
 
 1304             throw new CorrelationAttributeNormalizationException(
"Cannot get artifact instances without specified cases");
 
 1306         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 1311         StringBuilder inValuesBuilder = 
new StringBuilder(prepareGetInstancesSql(aType, values));
 
 1312         inValuesBuilder.append(sql);
 
 1313         inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining(
"', '")));
 
 1314         inValuesBuilder.append(
"')");
 
 1315         return getArtifactInstances(inValuesBuilder.toString(), aType);
 
 1330     private String prepareGetInstancesSql(CorrelationAttributeInstance.Type aType, List<String> values) 
throws CorrelationAttributeNormalizationException {
 
 1331         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 1335                 + 
".id as instance_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 " 
 1342                 + 
" LEFT JOIN cases ON " 
 1344                 + 
".case_id=cases.id" 
 1345                 + 
" LEFT JOIN organizations ON cases.org_id=organizations.id" 
 1346                 + 
" LEFT JOIN data_sources ON " 
 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(
"',");
 
 1358         inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); 
 
 1359         inValuesBuilder.append(
")");
 
 1360         return inValuesBuilder.toString();
 
 1377     private List<CorrelationAttributeInstance> getArtifactInstances(String sql, CorrelationAttributeInstance.Type aType) throws CorrelationAttributeNormalizationException, CentralRepoException {
 
 1378         Connection conn = connect();
 
 1379         List<CorrelationAttributeInstance> artifactInstances = 
new ArrayList<>();
 
 1380         CorrelationAttributeInstance artifactInstance;
 
 1381         PreparedStatement preparedStatement = null;
 
 1382         ResultSet resultSet = null;
 
 1384             preparedStatement = conn.prepareStatement(sql);
 
 1385             resultSet = preparedStatement.executeQuery();
 
 1386             while (resultSet.next()) {
 
 1387                 artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
 
 1388                 artifactInstances.add(artifactInstance);
 
 1390         } 
catch (SQLException ex) {
 
 1391             throw new CentralRepoException(
"Error getting artifact instances by artifactType and artifactValue.", ex); 
 
 1393             CentralRepoDbUtil.closeResultSet(resultSet);
 
 1394             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1395             CentralRepoDbUtil.closeConnection(conn);
 
 1397         return artifactInstances;
 
 1411     public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1412         String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
 
 1414         Connection conn = connect();
 
 1416         Long instanceCount = 0L;
 
 1417         PreparedStatement preparedStatement = null;
 
 1418         ResultSet resultSet = null;
 
 1420         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 1422                 = 
"SELECT count(*) FROM " 
 1427             preparedStatement = conn.prepareStatement(sql);
 
 1428             preparedStatement.setString(1, normalizedValue);
 
 1429             resultSet = preparedStatement.executeQuery();
 
 1431             instanceCount = resultSet.getLong(1);
 
 1432         } 
catch (SQLException ex) {
 
 1433             throw new CentralRepoException(
"Error getting count of artifact instances by artifactType and artifactValue.", ex); 
 
 1435             CentralRepoDbUtil.closeResultSet(resultSet);
 
 1436             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1437             CentralRepoDbUtil.closeConnection(conn);
 
 1440         return instanceCount;
 
 1444     public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1445         if (corAttr == null) {
 
 1446             throw new CentralRepoException(
"CorrelationAttribute is null");
 
 1448         Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
 
 1449         Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
 
 1450         Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
 
 1451         return commonalityPercentage.intValue();
 
 1465     public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1466         String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
 
 1468         Connection conn = connect();
 
 1470         Long instanceCount = 0L;
 
 1471         PreparedStatement preparedStatement = null;
 
 1472         ResultSet resultSet = null;
 
 1474         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 1476                 = 
"SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM " 
 1478                 + 
" WHERE value=?) AS " 
 1480                 + 
"_distinct_case_data_source_tuple";
 
 1483             preparedStatement = conn.prepareStatement(sql);
 
 1484             preparedStatement.setString(1, normalizedValue);
 
 1485             resultSet = preparedStatement.executeQuery();
 
 1487             instanceCount = resultSet.getLong(1);
 
 1488         } 
catch (SQLException ex) {
 
 1489             throw new CentralRepoException(
"Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); 
 
 1491             CentralRepoDbUtil.closeResultSet(resultSet);
 
 1492             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1493             CentralRepoDbUtil.closeConnection(conn);
 
 1496         return instanceCount;
 
 1500     public Long getCountCasesWithOtherInstances(CorrelationAttributeInstance instance) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1501         Long instanceCount = 0L;
 
 1502         if (instance != null) {
 
 1503             Long sourceObjID = instance.getFileObjectId();
 
 1505             int correlationCaseId = instance.getCorrelationCase().getID();
 
 1506             String normalizedValue = CorrelationAttributeNormalizer.normalize(instance.getCorrelationType(), instance.getCorrelationValue());
 
 1507             Connection conn = connect();
 
 1508             PreparedStatement preparedStatement = null;
 
 1509             String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(instance.getCorrelationType());
 
 1510             ResultSet resultSet = null;
 
 1512                 if (correlationCaseId > 0 && sourceObjID != null) {
 
 1515                             = 
"SELECT count(*) FROM (SELECT DISTINCT case_id FROM "  
 1517                             + 
" WHERE value=? AND NOT (file_obj_id=? AND case_id=?)) AS "  
 1519                             + 
"_other_case_count";
 
 1520                     preparedStatement = conn.prepareStatement(sql);
 
 1521                     preparedStatement.setString(1, normalizedValue);
 
 1522                     preparedStatement.setLong(2, sourceObjID);
 
 1523                     preparedStatement.setInt(3, correlationCaseId);
 
 1527                             = 
"SELECT count(*) FROM (SELECT DISTINCT case_id FROM "  
 1529                             + 
" WHERE value=? AS " 
 1531                             + 
"_other_case_count";
 
 1532                     preparedStatement = conn.prepareStatement(sql);
 
 1533                     preparedStatement.setString(1, normalizedValue);
 
 1535                 resultSet = preparedStatement.executeQuery();
 
 1537                 instanceCount = resultSet.getLong(1);
 
 1538             } 
catch (SQLException ex) {
 
 1539                 throw new CentralRepoException(
"Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); 
 
 1541                 CentralRepoDbUtil.closeResultSet(resultSet);
 
 1542                 CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1543                 CentralRepoDbUtil.closeConnection(conn);
 
 1547         return instanceCount;
 
 1551     public Long getCountUniqueDataSources() throws CentralRepoException {
 
 1552         Connection conn = connect();
 
 1554         Long instanceCount = 0L;
 
 1555         PreparedStatement preparedStatement = null;
 
 1556         ResultSet resultSet = null;
 
 1558         String stmt = 
"SELECT count(*) FROM data_sources";
 
 1561             preparedStatement = conn.prepareStatement(stmt);
 
 1562             resultSet = preparedStatement.executeQuery();
 
 1564             instanceCount = resultSet.getLong(1);
 
 1565         } 
catch (SQLException ex) {
 
 1566             throw new CentralRepoException(
"Error counting data sources.", ex); 
 
 1568             CentralRepoDbUtil.closeResultSet(resultSet);
 
 1569             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1570             CentralRepoDbUtil.closeConnection(conn);
 
 1573         return instanceCount;
 
 1588     public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) 
throws CentralRepoException {
 
 1589         Connection conn = connect();
 
 1591         Long instanceCount = 0L;
 
 1592         List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
 
 1593         PreparedStatement preparedStatement = null;
 
 1594         ResultSet resultSet = null;
 
 1597         String sql = 
"SELECT 0 ";
 
 1599         for (CorrelationAttributeInstance.Type type : artifactTypes) {
 
 1600             String table_name = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
 
 1602                     += 
"+ (SELECT count(*) FROM " 
 1604                     + 
" WHERE data_source_id=" + correlationDataSource.getID() + 
")";
 
 1607             preparedStatement = conn.prepareStatement(sql);
 
 1609             resultSet = preparedStatement.executeQuery();
 
 1611             instanceCount = resultSet.getLong(1);
 
 1612         } 
catch (SQLException ex) {
 
 1613             throw new CentralRepoException(
"Error counting artifact instances by caseName/dataSource.", ex); 
 
 1615             CentralRepoDbUtil.closeResultSet(resultSet);
 
 1616             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1617             CentralRepoDbUtil.closeConnection(conn);
 
 1620         return instanceCount;
 
 1631     public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) 
throws CentralRepoException {
 
 1633         if (eamArtifact.getCorrelationType() == null) {
 
 1634             throw new CentralRepoException(
"Correlation type is null");
 
 1637         synchronized (bulkArtifacts) {
 
 1638             if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) {
 
 1639                 bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), 
new ArrayList<>());
 
 1641             bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
 
 1642             bulkArtifactsCount++;
 
 1644             if (bulkArtifactsCount >= bulkArtifactsThreshold) {
 
 1645                 commitAttributeInstancesBulk();
 
 1655     protected abstract String getConflictClause();
 
 1662     public void commitAttributeInstancesBulk() throws CentralRepoException {
 
 1663         List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
 
 1665         Connection conn = connect();
 
 1666         PreparedStatement bulkPs = null;
 
 1669             synchronized (bulkArtifacts) {
 
 1670                 if (bulkArtifactsCount == 0) {
 
 1674                 for (String tableName : bulkArtifacts.keySet()) {
 
 1679                             + 
" (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) " 
 1680                             + 
"VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), " 
 1681                             + 
"(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) " 
 1682                             + getConflictClause();
 
 1684                     bulkPs = conn.prepareStatement(sql);
 
 1686                     Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
 
 1687                     for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
 
 1689                         if (!eamArtifact.getCorrelationValue().isEmpty()) {
 
 1691                             if (eamArtifact.getCorrelationCase() == null) {
 
 1692                                 throw new CentralRepoException(
"CorrelationAttributeInstance case is null for: " 
 1693                                         + 
"\n\tCorrelationArtifact ID: " + eamArtifact.getID()
 
 1694                                         + 
"\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
 
 1695                                         + 
"\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
 
 1697                             if (eamArtifact.getCorrelationDataSource() == null) {
 
 1698                                 throw new CentralRepoException(
"CorrelationAttributeInstance data source is null for: " 
 1699                                         + 
"\n\tCorrelationArtifact ID: " + eamArtifact.getID()
 
 1700                                         + 
"\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
 
 1701                                         + 
"\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
 
 1703                             if (eamArtifact.getKnownStatus() == null) {
 
 1704                                 throw new CentralRepoException(
"CorrelationAttributeInstance known status is null for: " 
 1705                                         + 
"\n\tCorrelationArtifact ID: " + eamArtifact.getID()
 
 1706                                         + 
"\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
 
 1707                                         + 
"\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
 
 1708                                         + 
"\n\tEam Instance: " 
 1709                                         + 
"\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
 
 1710                                         + 
"\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
 
 1713                             if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
 
 1714                                 bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
 
 1715                                 bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
 
 1716                                 bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
 
 1717                                 bulkPs.setString(4, eamArtifact.getCorrelationValue());
 
 1718                                 bulkPs.setString(5, eamArtifact.getFilePath());
 
 1719                                 bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
 
 1720                                 if (
"".equals(eamArtifact.getComment())) {
 
 1721                                     bulkPs.setNull(7, Types.INTEGER);
 
 1723                                     bulkPs.setString(7, eamArtifact.getComment());
 
 1725                                 bulkPs.setLong(8, eamArtifact.getFileObjectId());
 
 1728                                 logger.log(Level.WARNING, (
"Artifact value too long for central repository." 
 1729                                         + 
"\n\tCorrelationArtifact ID: " + eamArtifact.getID()
 
 1730                                         + 
"\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
 
 1731                                         + 
"\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
 
 1732                                         + 
"\n\tEam Instance: " 
 1733                                         + 
"\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
 
 1734                                         + 
"\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
 
 1735                                         + 
"\n\t\tFilePath: " + eamArtifact.getFilePath());
 
 1741                     bulkPs.executeBatch();
 
 1742                     bulkArtifacts.get(tableName).clear();
 
 1745                 TimingMetric timingMetric = HealthMonitor.getTimingMetric(
"Central Repository: Bulk insert");
 
 1746                 HealthMonitor.submitTimingMetric(timingMetric);
 
 1749                 bulkArtifactsCount = 0;
 
 1751         } 
catch (SQLException ex) {
 
 1752             throw new CentralRepoException(
"Error inserting bulk artifacts.", ex); 
 
 1754             CentralRepoDbUtil.closeStatement(bulkPs);
 
 1755             CentralRepoDbUtil.closeConnection(conn);
 
 1763     public void bulkInsertCases(List<CorrelationCase> cases) 
throws CentralRepoException {
 
 1764         if (cases == null) {
 
 1765             throw new CentralRepoException(
"cases argument is null");
 
 1768         if (cases.isEmpty()) {
 
 1772         Connection conn = connect();
 
 1775         PreparedStatement bulkPs = null;
 
 1777             String sql = 
"INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, " 
 1778                     + 
"examiner_name, examiner_email, examiner_phone, notes) " 
 1779                     + 
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) " 
 1780                     + getConflictClause();
 
 1781             bulkPs = conn.prepareStatement(sql);
 
 1783             for (CorrelationCase eamCase : cases) {
 
 1784                 bulkPs.setString(1, eamCase.getCaseUUID());
 
 1785                 if (null == eamCase.getOrg()) {
 
 1786                     bulkPs.setNull(2, Types.INTEGER);
 
 1788                     bulkPs.setInt(2, eamCase.getOrg().getOrgID());
 
 1790                 bulkPs.setString(3, eamCase.getDisplayName());
 
 1791                 bulkPs.setString(4, eamCase.getCreationDate());
 
 1793                 if (
"".equals(eamCase.getCaseNumber())) {
 
 1794                     bulkPs.setNull(5, Types.INTEGER);
 
 1796                     bulkPs.setString(5, eamCase.getCaseNumber());
 
 1798                 if (
"".equals(eamCase.getExaminerName())) {
 
 1799                     bulkPs.setNull(6, Types.INTEGER);
 
 1801                     bulkPs.setString(6, eamCase.getExaminerName());
 
 1803                 if (
"".equals(eamCase.getExaminerEmail())) {
 
 1804                     bulkPs.setNull(7, Types.INTEGER);
 
 1806                     bulkPs.setString(7, eamCase.getExaminerEmail());
 
 1808                 if (
"".equals(eamCase.getExaminerPhone())) {
 
 1809                     bulkPs.setNull(8, Types.INTEGER);
 
 1811                     bulkPs.setString(8, eamCase.getExaminerPhone());
 
 1813                 if (
"".equals(eamCase.getNotes())) {
 
 1814                     bulkPs.setNull(9, Types.INTEGER);
 
 1816                     bulkPs.setString(9, eamCase.getNotes());
 
 1824                 if (counter >= bulkArtifactsThreshold) {
 
 1825                     bulkPs.executeBatch();
 
 1830             bulkPs.executeBatch();
 
 1831         } 
catch (SQLException ex) {
 
 1832             throw new CentralRepoException(
"Error inserting bulk cases.", ex); 
 
 1834             CentralRepoDbUtil.closeStatement(bulkPs);
 
 1835             CentralRepoDbUtil.closeConnection(conn);
 
 1849     public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) 
throws CentralRepoException {
 
 1851         if (eamArtifact == null) {
 
 1852             throw new CentralRepoException(
"CorrelationAttributeInstance is null");
 
 1854         if (eamArtifact.getCorrelationCase() == null) {
 
 1855             throw new CentralRepoException(
"Correlation case is null");
 
 1857         if (eamArtifact.getCorrelationDataSource() == null) {
 
 1858             throw new CentralRepoException(
"Correlation data source is null");
 
 1860         Connection conn = connect();
 
 1861         PreparedStatement preparedQuery = null;
 
 1862         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
 
 1867                 + 
"WHERE case_id=? " 
 1868                 + 
"AND data_source_id=? " 
 1870                 + 
"AND file_path=?";
 
 1873             preparedQuery = conn.prepareStatement(sqlUpdate);
 
 1874             preparedQuery.setString(1, eamArtifact.getComment());
 
 1875             preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
 
 1876             preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
 
 1877             preparedQuery.setString(4, eamArtifact.getCorrelationValue());
 
 1878             preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
 
 1879             preparedQuery.executeUpdate();
 
 1880         } 
catch (SQLException ex) {
 
 1881             throw new CentralRepoException(
"Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); 
 
 1883             CentralRepoDbUtil.closeStatement(preparedQuery);
 
 1884             CentralRepoDbUtil.closeConnection(conn);
 
 1903     public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
 
 1904             CorrelationDataSource correlationDataSource, 
long objectID) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1906         if (correlationCase == null) {
 
 1907             throw new CentralRepoException(
"Correlation case is null");
 
 1910         Connection conn = connect();
 
 1912         PreparedStatement preparedStatement = null;
 
 1913         ResultSet resultSet = null;
 
 1914         CorrelationAttributeInstance correlationAttributeInstance = null;
 
 1918             String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
 
 1920                     = 
"SELECT id, value, file_path, known_status, comment FROM " 
 1922                     + 
" WHERE case_id=?" 
 1923                     + 
" AND file_obj_id=?";
 
 1925             preparedStatement = conn.prepareStatement(sql);
 
 1926             preparedStatement.setInt(1, correlationCase.getID());
 
 1927             preparedStatement.setInt(2, (
int) objectID);
 
 1928             resultSet = preparedStatement.executeQuery();
 
 1929             if (resultSet.next()) {
 
 1930                 int instanceId = resultSet.getInt(1);
 
 1931                 String value = resultSet.getString(2);
 
 1932                 String filePath = resultSet.getString(3);
 
 1933                 int knownStatus = resultSet.getInt(4);
 
 1934                 String comment = resultSet.getString(5);
 
 1936                 correlationAttributeInstance = 
new CorrelationAttributeInstance(type, value,
 
 1937                         instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
 
 1939         } 
catch (SQLException ex) {
 
 1940             throw new CentralRepoException(
"Error getting notable artifact instances.", ex); 
 
 1942             CentralRepoDbUtil.closeResultSet(resultSet);
 
 1943             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 1944             CentralRepoDbUtil.closeConnection(conn);
 
 1947         return correlationAttributeInstance;
 
 1965     public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
 
 1966             CorrelationDataSource correlationDataSource, String value, String filePath) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 1968         if (correlationCase == null) {
 
 1969             throw new CentralRepoException(
"Correlation case is null");
 
 1971         if (correlationDataSource == null) {
 
 1972             throw new CentralRepoException(
"Correlation data source is null");
 
 1974         if (filePath == null) {
 
 1975             throw new CentralRepoException(
"Correlation file path is null");
 
 1978         Connection conn = connect();
 
 1980         PreparedStatement preparedStatement = null;
 
 1981         ResultSet resultSet = null;
 
 1982         CorrelationAttributeInstance correlationAttributeInstance = null;
 
 1985             String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
 
 1987             String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
 
 1989                     = 
"SELECT id, known_status, comment FROM " 
 1991                     + 
" WHERE case_id=?" 
 1992                     + 
" AND data_source_id=?" 
 1994                     + 
" AND file_path=?";
 
 1996             preparedStatement = conn.prepareStatement(sql);
 
 1997             preparedStatement.setInt(1, correlationCase.getID());
 
 1998             preparedStatement.setInt(2, correlationDataSource.getID());
 
 1999             preparedStatement.setString(3, normalizedValue);
 
 2000             preparedStatement.setString(4, filePath.toLowerCase());
 
 2001             resultSet = preparedStatement.executeQuery();
 
 2002             if (resultSet.next()) {
 
 2003                 int instanceId = resultSet.getInt(1);
 
 2004                 int knownStatus = resultSet.getInt(2);
 
 2005                 String comment = resultSet.getString(3);
 
 2007                 correlationAttributeInstance = 
new CorrelationAttributeInstance(type, value,
 
 2008                         instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
 
 2010         } 
catch (SQLException ex) {
 
 2011             throw new CentralRepoException(
"Error getting notable artifact instances.", ex); 
 
 2013             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2014             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2015             CentralRepoDbUtil.closeConnection(conn);
 
 2018         return correlationAttributeInstance;
 
 2032     public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws CentralRepoException {
 
 2033         if (eamArtifact == null) {
 
 2034             throw new CentralRepoException(
"CorrelationAttribute is null");
 
 2036         if (knownStatus == null) {
 
 2037             throw new CentralRepoException(
"Known status is null");
 
 2040         if (eamArtifact.getCorrelationCase() == null) {
 
 2041             throw new CentralRepoException(
"Correlation case is null");
 
 2043         if (eamArtifact.getCorrelationDataSource() == null) {
 
 2044             throw new CentralRepoException(
"Correlation data source is null");
 
 2047         Connection conn = connect();
 
 2049         PreparedStatement preparedUpdate = null;
 
 2050         PreparedStatement preparedQuery = null;
 
 2051         ResultSet resultSet = null;
 
 2053         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
 
 2058                 + 
" WHERE case_id=? " 
 2059                 + 
"AND data_source_id=? " 
 2061                 + 
"AND file_path=?";
 
 2066                 + 
" SET known_status=? WHERE id=?";
 
 2069             preparedQuery = conn.prepareStatement(sqlQuery);
 
 2070             preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
 
 2071             preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
 
 2072             preparedQuery.setString(3, eamArtifact.getCorrelationValue());
 
 2073             preparedQuery.setString(4, eamArtifact.getFilePath());
 
 2074             resultSet = preparedQuery.executeQuery();
 
 2075             if (resultSet.next()) {
 
 2076                 int instance_id = resultSet.getInt(
"id");
 
 2077                 preparedUpdate = conn.prepareStatement(sqlUpdate);
 
 2079                 preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
 
 2080                 preparedUpdate.setInt(2, instance_id);
 
 2082                 preparedUpdate.executeUpdate();
 
 2089                 CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
 
 2090                 if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
 
 2091                     newDataSource(eamArtifact.getCorrelationDataSource());
 
 2093                 eamArtifact.setKnownStatus(knownStatus);
 
 2094                 addArtifactInstance(eamArtifact);
 
 2097         } 
catch (SQLException ex) {
 
 2098             throw new CentralRepoException(
"Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); 
 
 2100             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2101             CentralRepoDbUtil.closeStatement(preparedUpdate);
 
 2102             CentralRepoDbUtil.closeStatement(preparedQuery);
 
 2103             CentralRepoDbUtil.closeConnection(conn);
 
 2116     public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2118         String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
 
 2120         Connection conn = connect();
 
 2122         Long badInstances = 0L;
 
 2123         PreparedStatement preparedStatement = null;
 
 2124         ResultSet resultSet = null;
 
 2126         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 2128                 = 
"SELECT count(*) FROM " 
 2130                 + 
" WHERE value=? AND known_status=?";
 
 2133             preparedStatement = conn.prepareStatement(sql);
 
 2134             preparedStatement.setString(1, normalizedValue);
 
 2135             preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
 
 2136             resultSet = preparedStatement.executeQuery();
 
 2138             badInstances = resultSet.getLong(1);
 
 2139         } 
catch (SQLException ex) {
 
 2140             throw new CentralRepoException(
"Error getting count of notable artifact instances.", ex); 
 
 2142             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2143             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2144             CentralRepoDbUtil.closeConnection(conn);
 
 2147         return badInstances;
 
 2163     public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2165         String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
 
 2167         Connection conn = connect();
 
 2169         Collection<String> caseNames = 
new LinkedHashSet<>();
 
 2171         PreparedStatement preparedStatement = null;
 
 2172         ResultSet resultSet = null;
 
 2174         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 2176                 = 
"SELECT DISTINCT case_name FROM " 
 2178                 + 
" INNER JOIN cases ON " 
 2180                 + 
".case_id=cases.id WHERE " 
 2184                 + 
".known_status=?";
 
 2187             preparedStatement = conn.prepareStatement(sql);
 
 2188             preparedStatement.setString(1, normalizedValue);
 
 2189             preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
 
 2190             resultSet = preparedStatement.executeQuery();
 
 2191             while (resultSet.next()) {
 
 2192                 caseNames.add(resultSet.getString(
"case_name"));
 
 2194         } 
catch (SQLException ex) {
 
 2195             throw new CentralRepoException(
"Error getting notable artifact instances.", ex); 
 
 2197             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2198             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2199             CentralRepoDbUtil.closeConnection(conn);
 
 2202         return caseNames.stream().collect(Collectors.toList());
 
 2218     public List<String> getListCasesHavingArtifactInstances(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2220         String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
 
 2222         Connection conn = connect();
 
 2224         Collection<String> caseNames = 
new LinkedHashSet<>();
 
 2226         PreparedStatement preparedStatement = null;
 
 2227         ResultSet resultSet = null;
 
 2229         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
 
 2231                 = 
"SELECT DISTINCT case_name FROM " 
 2233                 + 
" INNER JOIN cases ON " 
 2235                 + 
".case_id=cases.id WHERE " 
 2240             preparedStatement = conn.prepareStatement(sql);
 
 2241             preparedStatement.setString(1, normalizedValue);
 
 2242             resultSet = preparedStatement.executeQuery();
 
 2243             while (resultSet.next()) {
 
 2244                 caseNames.add(resultSet.getString(
"case_name"));
 
 2246         } 
catch (SQLException ex) {
 
 2247             throw new CentralRepoException(
"Error getting notable artifact instances.", ex); 
 
 2249             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2250             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2251             CentralRepoDbUtil.closeConnection(conn);
 
 2254         return caseNames.stream().collect(Collectors.toList());
 
 2265     public void deleteReferenceSet(
int referenceSetID) 
throws CentralRepoException {
 
 2266         deleteReferenceSetEntries(referenceSetID);
 
 2267         deleteReferenceSetEntry(referenceSetID);
 
 2277     private void deleteReferenceSetEntry(
int referenceSetID) 
throws CentralRepoException {
 
 2278         Connection conn = connect();
 
 2280         PreparedStatement preparedStatement = null;
 
 2281         String sql = 
"DELETE FROM reference_sets WHERE id=?";
 
 2284             preparedStatement = conn.prepareStatement(sql);
 
 2285             preparedStatement.setInt(1, referenceSetID);
 
 2286             preparedStatement.executeUpdate();
 
 2287         } 
catch (SQLException ex) {
 
 2288             throw new CentralRepoException(
"Error deleting reference set " + referenceSetID, ex); 
 
 2290             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2291             CentralRepoDbUtil.closeConnection(conn);
 
 2303     private void deleteReferenceSetEntries(
int referenceSetID) 
throws CentralRepoException {
 
 2304         Connection conn = connect();
 
 2306         PreparedStatement preparedStatement = null;
 
 2307         String sql = 
"DELETE FROM %s WHERE reference_set_id=?";
 
 2310         String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
 
 2313             preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
 
 2314             preparedStatement.setInt(1, referenceSetID);
 
 2315             preparedStatement.executeUpdate();
 
 2316         } 
catch (SQLException ex) {
 
 2317             throw new CentralRepoException(
"Error deleting files from reference set " + referenceSetID, ex); 
 
 2319             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2320             CentralRepoDbUtil.closeConnection(conn);
 
 2338     public boolean referenceSetIsValid(
int referenceSetID, String setName, String version) 
throws CentralRepoException {
 
 2339         CentralRepoFileSet refSet = this.getReferenceSetByID(referenceSetID);
 
 2340         if (refSet == null) {
 
 2344         return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
 
 2359     public boolean isFileHashInReferenceSet(String hash, 
int referenceSetID) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2360         return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
 
 2364     public HashHitInfo lookupHash(String hash, 
int referenceSetID) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2365         int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID;
 
 2366         String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash);
 
 2368         Connection conn = connect();
 
 2370         PreparedStatement preparedStatement = null;
 
 2371         ResultSet resultSet = null;
 
 2372         String sql = 
"SELECT value,comment FROM %s WHERE value=? AND reference_set_id=?";
 
 2374         String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
 
 2377             preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
 
 2378             preparedStatement.setString(1, normalizeValued);
 
 2379             preparedStatement.setInt(2, referenceSetID);
 
 2380             resultSet = preparedStatement.executeQuery();
 
 2381             if (resultSet.next()) {
 
 2382                 String comment = resultSet.getString(
"comment");
 
 2383                 String hashFound = resultSet.getString(
"value");
 
 2384                 HashHitInfo found = 
new HashHitInfo(hashFound, 
"", 
"");
 
 2385                 found.addComment(comment);
 
 2390         } 
catch (SQLException ex) {
 
 2391             throw new CentralRepoException(
"Error determining if value (" + normalizeValued + 
") is in reference set " + referenceSetID, ex); 
 
 2393             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2394             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2395             CentralRepoDbUtil.closeConnection(conn);
 
 2409     public boolean isValueInReferenceSet(String value, 
int referenceSetID, 
int correlationTypeID) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2411         String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
 
 2413         Connection conn = connect();
 
 2415         Long matchingInstances = 0L;
 
 2416         PreparedStatement preparedStatement = null;
 
 2417         ResultSet resultSet = null;
 
 2418         String sql = 
"SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
 
 2420         String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
 
 2423             preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
 
 2424             preparedStatement.setString(1, normalizeValued);
 
 2425             preparedStatement.setInt(2, referenceSetID);
 
 2426             resultSet = preparedStatement.executeQuery();
 
 2428             matchingInstances = resultSet.getLong(1);
 
 2429         } 
catch (SQLException ex) {
 
 2430             throw new CentralRepoException(
"Error determining if value (" + normalizeValued + 
") is in reference set " + referenceSetID, ex); 
 
 2432             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2433             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2434             CentralRepoDbUtil.closeConnection(conn);
 
 2437         return 0 < matchingInstances;
 
 2449     public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 2452         String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
 
 2455         if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
 
 2459         Connection conn = connect();
 
 2461         Long badInstances = 0L;
 
 2462         PreparedStatement preparedStatement = null;
 
 2463         ResultSet resultSet = null;
 
 2464         String sql = 
"SELECT count(*) FROM %s WHERE value=? AND known_status=?";
 
 2467             preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
 
 2468             preparedStatement.setString(1, normalizeValued);
 
 2469             preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
 
 2470             resultSet = preparedStatement.executeQuery();
 
 2472             badInstances = resultSet.getLong(1);
 
 2473         } 
catch (SQLException ex) {
 
 2474             throw new CentralRepoException(
"Error determining if artifact is notable by reference.", ex); 
 
 2476             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2477             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2478             CentralRepoDbUtil.closeConnection(conn);
 
 2481         return 0 < badInstances;
 
 2493     public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) 
throws CentralRepoException {
 
 2495             throw new CentralRepoException(
"Correlation type is null");
 
 2498         if (instanceTableCallback == null) {
 
 2499             throw new CentralRepoException(
"Callback interface is null");
 
 2502         Connection conn = connect();
 
 2503         PreparedStatement preparedStatement = null;
 
 2504         ResultSet resultSet = null;
 
 2505         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
 
 2506         StringBuilder sql = 
new StringBuilder();
 
 2507         sql.append(
"select * from ");
 
 2508         sql.append(tableName);
 
 2511             preparedStatement = conn.prepareStatement(sql.toString());
 
 2512             resultSet = preparedStatement.executeQuery();
 
 2513             instanceTableCallback.process(resultSet);
 
 2514         } 
catch (SQLException ex) {
 
 2515             throw new CentralRepoException(
"Error getting all artifact instances from instances table", ex);
 
 2517             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2518             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2519             CentralRepoDbUtil.closeConnection(conn);
 
 2533     public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) 
throws CentralRepoException {
 
 2535             throw new CentralRepoException(
"Correlation type is null");
 
 2538         if (instanceTableCallback == null) {
 
 2539             throw new CentralRepoException(
"Callback interface is null");
 
 2542         if (whereClause == null) {
 
 2543             throw new CentralRepoException(
"Where clause is null");
 
 2546         Connection conn = connect();
 
 2547         PreparedStatement preparedStatement = null;
 
 2548         ResultSet resultSet = null;
 
 2549         String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
 
 2550         StringBuilder sql = 
new StringBuilder(300);
 
 2551         sql.append(
"select * from ")
 
 2554                 .append(whereClause);
 
 2557             preparedStatement = conn.prepareStatement(sql.toString());
 
 2558             resultSet = preparedStatement.executeQuery();
 
 2559             instanceTableCallback.process(resultSet);
 
 2560         } 
catch (SQLException ex) {
 
 2561             throw new CentralRepoException(
"Error getting all artifact instances from instances table", ex);
 
 2563             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2564             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2565             CentralRepoDbUtil.closeConnection(conn);
 
 2578     public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) 
throws CentralRepoException {
 
 2580         if (instanceTableCallback == null) {
 
 2581             throw new CentralRepoException(
"Callback interface is null");
 
 2584         if (selectClause == null) {
 
 2585             throw new CentralRepoException(
"Select clause is null");
 
 2588         Connection conn = connect();
 
 2589         PreparedStatement preparedStatement = null;
 
 2590         ResultSet resultSet = null;
 
 2591         StringBuilder sql = 
new StringBuilder(300);
 
 2592         sql.append(
"select ")
 
 2593                 .append(selectClause);
 
 2596             preparedStatement = conn.prepareStatement(sql.toString());
 
 2597             resultSet = preparedStatement.executeQuery();
 
 2598             instanceTableCallback.process(resultSet);
 
 2599         } 
catch (SQLException ex) {
 
 2600             throw new CentralRepoException(
"Error running query", ex);
 
 2602             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2603             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2604             CentralRepoDbUtil.closeConnection(conn);
 
 2609     public void executeCommand(String sql, List<Object> params) 
throws CentralRepoException {
 
 2611         try (Connection conn = connect();) {
 
 2613             PreparedStatement preparedStatement = conn.prepareStatement(sql);
 
 2616             if (params != null) {
 
 2618                 for (Object param : params) {
 
 2619                     preparedStatement.setObject(paramIndex, param);
 
 2624             preparedStatement.executeUpdate();
 
 2625         } 
catch (SQLException ex) {
 
 2626             throw new CentralRepoException(String.format(
"Error executing prepared statement for SQL %s", sql), ex);
 
 2631     public void executeQuery(String sql, List<Object> params, CentralRepositoryDbQueryCallback queryCallback) 
throws CentralRepoException {
 
 2632         if (queryCallback == null) {
 
 2633             throw new CentralRepoException(
"Query callback is null");
 
 2636         try (Connection conn = connect();) {
 
 2637             PreparedStatement preparedStatement = conn.prepareStatement(sql);
 
 2640             if (params != null) {
 
 2642                 for (Object param : params) {
 
 2643                     preparedStatement.setObject(paramIndex, param);
 
 2648             try (ResultSet resultSet = preparedStatement.executeQuery();) {
 
 2649                 queryCallback.process(resultSet);
 
 2651         } 
catch (SQLException ex) {
 
 2652             throw new CentralRepoException(String.format(
"Error executing prepared statement for SQL query %s", sql), ex);
 
 2657     public CentralRepoOrganization newOrganization(CentralRepoOrganization eamOrg) 
throws CentralRepoException {
 
 2658         if (eamOrg == null) {
 
 2659             throw new CentralRepoException(
"EamOrganization is null");
 
 2660         } 
else if (eamOrg.getOrgID() != -1) {
 
 2661             throw new CentralRepoException(
"EamOrganization already has an ID");
 
 2664         Connection conn = connect();
 
 2665         ResultSet generatedKeys = null;
 
 2666         PreparedStatement preparedStatement = null;
 
 2667         String sql = 
"INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) " 
 2668                 + getConflictClause();
 
 2671             preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
 
 2672             preparedStatement.setString(1, eamOrg.getName());
 
 2673             preparedStatement.setString(2, eamOrg.getPocName());
 
 2674             preparedStatement.setString(3, eamOrg.getPocEmail());
 
 2675             preparedStatement.setString(4, eamOrg.getPocPhone());
 
 2677             preparedStatement.executeUpdate();
 
 2678             generatedKeys = preparedStatement.getGeneratedKeys();
 
 2679             if (generatedKeys.next()) {
 
 2680                 eamOrg.setOrgID((
int) generatedKeys.getLong(1));
 
 2683                 throw new SQLException(
"Creating user failed, no ID obtained.");
 
 2685         } 
catch (SQLException ex) {
 
 2686             throw new CentralRepoException(
"Error inserting new organization.", ex); 
 
 2688             CentralRepoDbUtil.closeResultSet(generatedKeys);
 
 2689             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2690             CentralRepoDbUtil.closeConnection(conn);
 
 2702     public List<CentralRepoOrganization> getOrganizations() throws CentralRepoException {
 
 2703         Connection conn = connect();
 
 2705         List<CentralRepoOrganization> orgs = 
new ArrayList<>();
 
 2706         PreparedStatement preparedStatement = null;
 
 2707         ResultSet resultSet = null;
 
 2708         String sql = 
"SELECT * FROM organizations";
 
 2711             preparedStatement = conn.prepareStatement(sql);
 
 2712             resultSet = preparedStatement.executeQuery();
 
 2713             while (resultSet.next()) {
 
 2714                 orgs.add(getEamOrganizationFromResultSet(resultSet));
 
 2718         } 
catch (SQLException ex) {
 
 2719             throw new CentralRepoException(
"Error getting all organizations.", ex); 
 
 2721             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2722             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2723             CentralRepoDbUtil.closeConnection(conn);
 
 2737     public CentralRepoOrganization getOrganizationByID(
int orgID) 
throws CentralRepoException {
 
 2738         Connection conn = connect();
 
 2740         PreparedStatement preparedStatement = null;
 
 2741         ResultSet resultSet = null;
 
 2742         String sql = 
"SELECT * FROM organizations WHERE id=?";
 
 2745             preparedStatement = conn.prepareStatement(sql);
 
 2746             preparedStatement.setInt(1, orgID);
 
 2747             resultSet = preparedStatement.executeQuery();
 
 2749             return getEamOrganizationFromResultSet(resultSet);
 
 2751         } 
catch (SQLException ex) {
 
 2752             throw new CentralRepoException(
"Error getting organization by id.", ex); 
 
 2754             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2755             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2756             CentralRepoDbUtil.closeConnection(conn);
 
 2770     public CentralRepoOrganization getReferenceSetOrganization(
int referenceSetID) 
throws CentralRepoException {
 
 2772         CentralRepoFileSet globalSet = getReferenceSetByID(referenceSetID);
 
 2773         if (globalSet == null) {
 
 2774             throw new CentralRepoException(
"Reference set with ID " + referenceSetID + 
" not found");
 
 2776         return (getOrganizationByID(globalSet.getOrgID()));
 
 2786     private void testArgument(CentralRepoOrganization 
org) 
throws CentralRepoException {
 
 2788             throw new CentralRepoException(
"EamOrganization is null");
 
 2789         } 
else if (
org.getOrgID() == -1) {
 
 2790             throw new CentralRepoException(
"Organization  has -1 row ID");
 
 2806     public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) 
throws CentralRepoException {
 
 2808         String querySQL = 
"SELECT * FROM examiners WHERE login_name = '" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + 
"'";
 
 2809         try (Connection connection = connect();
 
 2810                 Statement statement = connection.createStatement();
 
 2811                 ResultSet resultSet = statement.executeQuery(querySQL);) {
 
 2813             if (resultSet.next()) {
 
 2814                 return new CentralRepoExaminer(resultSet.getLong(
"id"), resultSet.getString(
"login_name"));
 
 2819                     switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
 
 2821                             insertSQL = 
"INSERT INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + 
"')" + getConflictClause();  
 
 2824                             insertSQL = 
"INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + 
"')"; 
 
 2827                             throw new CentralRepoException(String.format(
"Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); 
 
 2829                     statement.execute(insertSQL);
 
 2832                     try (ResultSet resultSet2 = statement.executeQuery(querySQL)) {
 
 2833                         if (resultSet2.next()) {
 
 2834                             return new CentralRepoExaminer(resultSet2.getLong(
"id"), resultSet2.getString(
"login_name"));
 
 2836                             throw new CentralRepoException(
"Error getting examiner for name = " + examinerLoginName);
 
 2840                 } 
catch (SQLException ex) {
 
 2841                     throw new CentralRepoException(
"Error inserting row in examiners", ex);
 
 2845         } 
catch (SQLException ex) {
 
 2846             throw new CentralRepoException(
"Error getting examiner for name = " + examinerLoginName, ex);
 
 2859     public void updateOrganization(CentralRepoOrganization updatedOrganization) 
throws CentralRepoException {
 
 2860         testArgument(updatedOrganization);
 
 2862         Connection conn = connect();
 
 2863         PreparedStatement preparedStatement = null;
 
 2864         String sql = 
"UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
 
 2866             preparedStatement = conn.prepareStatement(sql);
 
 2867             preparedStatement.setString(1, updatedOrganization.getName());
 
 2868             preparedStatement.setString(2, updatedOrganization.getPocName());
 
 2869             preparedStatement.setString(3, updatedOrganization.getPocEmail());
 
 2870             preparedStatement.setString(4, updatedOrganization.getPocPhone());
 
 2871             preparedStatement.setInt(5, updatedOrganization.getOrgID());
 
 2872             preparedStatement.executeUpdate();
 
 2873         } 
catch (SQLException ex) {
 
 2874             throw new CentralRepoException(
"Error updating organization.", ex); 
 
 2876             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 2877             CentralRepoDbUtil.closeConnection(conn);
 
 2882     public void deleteOrganization(CentralRepoOrganization organizationToDelete) 
throws CentralRepoException {
 
 2883         testArgument(organizationToDelete);
 
 2885         Connection conn = connect();
 
 2886         PreparedStatement checkIfUsedStatement = null;
 
 2887         ResultSet resultSet = null;
 
 2888         String checkIfUsedSql = 
"SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
 
 2889         PreparedStatement deleteOrgStatement = null;
 
 2890         String deleteOrgSql = 
"DELETE FROM organizations WHERE id=?";
 
 2892             checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
 
 2893             checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
 
 2894             checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
 
 2895             resultSet = checkIfUsedStatement.executeQuery();
 
 2897             if (resultSet.getLong(1) > 0) {
 
 2898                 throw new CentralRepoException(
"Can not delete organization which is currently in use by a case or reference set in the central repository.");
 
 2900             deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
 
 2901             deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
 
 2902             deleteOrgStatement.executeUpdate();
 
 2903         } 
catch (SQLException ex) {
 
 2904             throw new CentralRepoException(
"Error executing query when attempting to delete organization by id.", ex); 
 
 2906             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2907             CentralRepoDbUtil.closeStatement(checkIfUsedStatement);
 
 2908             CentralRepoDbUtil.closeStatement(deleteOrgStatement);
 
 2909             CentralRepoDbUtil.closeConnection(conn);
 
 2923     public int newReferenceSet(CentralRepoFileSet eamGlobalSet) 
throws CentralRepoException {
 
 2924         if (eamGlobalSet == null) {
 
 2925             throw new CentralRepoException(
"EamGlobalSet is null");
 
 2928         if (eamGlobalSet.getFileKnownStatus() == null) {
 
 2929             throw new CentralRepoException(
"File known status on the EamGlobalSet is null");
 
 2932         if (eamGlobalSet.getType() == null) {
 
 2933             throw new CentralRepoException(
"Type on the EamGlobalSet is null");
 
 2936         Connection conn = connect();
 
 2938         PreparedStatement preparedStatement1 = null;
 
 2939         PreparedStatement preparedStatement2 = null;
 
 2940         ResultSet resultSet = null;
 
 2941         String sql1 = 
"INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) " 
 2942                 + getConflictClause();
 
 2943         String sql2 = 
"SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
 
 2946             preparedStatement1 = conn.prepareStatement(sql1);
 
 2947             preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
 
 2948             preparedStatement1.setString(2, eamGlobalSet.getSetName());
 
 2949             preparedStatement1.setString(3, eamGlobalSet.getVersion());
 
 2950             preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
 
 2951             preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
 
 2952             preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
 
 2953             preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
 
 2955             preparedStatement1.executeUpdate();
 
 2957             preparedStatement2 = conn.prepareStatement(sql2);
 
 2958             preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
 
 2959             preparedStatement2.setString(2, eamGlobalSet.getSetName());
 
 2960             preparedStatement2.setString(3, eamGlobalSet.getVersion());
 
 2961             preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
 
 2963             resultSet = preparedStatement2.executeQuery();
 
 2965             return resultSet.getInt(
"id");
 
 2967         } 
catch (SQLException ex) {
 
 2968             throw new CentralRepoException(
"Error inserting new global set.", ex); 
 
 2970             CentralRepoDbUtil.closeResultSet(resultSet);
 
 2971             CentralRepoDbUtil.closeStatement(preparedStatement1);
 
 2972             CentralRepoDbUtil.closeStatement(preparedStatement2);
 
 2973             CentralRepoDbUtil.closeConnection(conn);
 
 2987     public CentralRepoFileSet getReferenceSetByID(
int referenceSetID) 
throws CentralRepoException {
 
 2988         Connection conn = connect();
 
 2990         PreparedStatement preparedStatement1 = null;
 
 2991         ResultSet resultSet = null;
 
 2992         String sql1 = 
"SELECT * FROM reference_sets WHERE id=?";
 
 2995             preparedStatement1 = conn.prepareStatement(sql1);
 
 2996             preparedStatement1.setInt(1, referenceSetID);
 
 2997             resultSet = preparedStatement1.executeQuery();
 
 2998             if (resultSet.next()) {
 
 2999                 return getEamGlobalSetFromResultSet(resultSet);
 
 3004         } 
catch (SQLException ex) {
 
 3005             throw new CentralRepoException(
"Error getting reference set by id.", ex); 
 
 3007             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3008             CentralRepoDbUtil.closeStatement(preparedStatement1);
 
 3009             CentralRepoDbUtil.closeConnection(conn);
 
 3023     public List<CentralRepoFileSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
 
 3025         if (correlationType == null) {
 
 3026             throw new CentralRepoException(
"Correlation type is null");
 
 3029         List<CentralRepoFileSet> results = 
new ArrayList<>();
 
 3030         Connection conn = connect();
 
 3032         PreparedStatement preparedStatement1 = null;
 
 3033         ResultSet resultSet = null;
 
 3034         String sql1 = 
"SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
 
 3037             preparedStatement1 = conn.prepareStatement(sql1);
 
 3038             resultSet = preparedStatement1.executeQuery();
 
 3039             while (resultSet.next()) {
 
 3040                 results.add(getEamGlobalSetFromResultSet(resultSet));
 
 3043         } 
catch (SQLException ex) {
 
 3044             throw new CentralRepoException(
"Error getting reference sets.", ex); 
 
 3046             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3047             CentralRepoDbUtil.closeStatement(preparedStatement1);
 
 3048             CentralRepoDbUtil.closeConnection(conn);
 
 3063     public void addReferenceInstance(CentralRepoFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
 
 3064         if (eamGlobalFileInstance.getKnownStatus() == null) {
 
 3065             throw new CentralRepoException(
"Known status of EamGlobalFileInstance is null");
 
 3067         if (correlationType == null) {
 
 3068             throw new CentralRepoException(
"Correlation type is null");
 
 3071         Connection conn = connect();
 
 3073         PreparedStatement preparedStatement = null;
 
 3075         String sql = 
"INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) " 
 3076                 + getConflictClause();
 
 3079             preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(correlationType)));
 
 3080             preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
 
 3081             preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
 
 3082             preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
 
 3083             preparedStatement.setString(4, eamGlobalFileInstance.getComment());
 
 3084             preparedStatement.executeUpdate();
 
 3085         } 
catch (SQLException ex) {
 
 3086             throw new CentralRepoException(
"Error inserting new reference instance into reference_ table.", ex); 
 
 3088             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3089             CentralRepoDbUtil.closeConnection(conn);
 
 3106     public boolean referenceSetExists(String referenceSetName, String version) 
throws CentralRepoException {
 
 3107         Connection conn = connect();
 
 3109         PreparedStatement preparedStatement1 = null;
 
 3110         ResultSet resultSet = null;
 
 3111         String sql1 = 
"SELECT * FROM reference_sets WHERE set_name=? AND version=?";
 
 3114             preparedStatement1 = conn.prepareStatement(sql1);
 
 3115             preparedStatement1.setString(1, referenceSetName);
 
 3116             preparedStatement1.setString(2, version);
 
 3117             resultSet = preparedStatement1.executeQuery();
 
 3118             return (resultSet.next());
 
 3120         } 
catch (SQLException ex) {
 
 3121             throw new CentralRepoException(
"Error testing whether reference set exists (name: " + referenceSetName
 
 3122                     + 
" version: " + version, ex); 
 
 3124             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3125             CentralRepoDbUtil.closeStatement(preparedStatement1);
 
 3126             CentralRepoDbUtil.closeConnection(conn);
 
 3136     public void bulkInsertReferenceTypeEntries(Set<CentralRepoFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws CentralRepoException {
 
 3137         if (contentType == null) {
 
 3138             throw new CentralRepoException(
"Correlation type is null");
 
 3140         if (globalInstances == null) {
 
 3141             throw new CentralRepoException(
"Null set of EamGlobalFileInstance");
 
 3144         Connection conn = connect();
 
 3146         PreparedStatement bulkPs = null;
 
 3148             conn.setAutoCommit(
false);
 
 3151             String sql = 
"INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) " 
 3152                     + getConflictClause();
 
 3154             bulkPs = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(contentType)));
 
 3156             for (CentralRepoFileInstance globalInstance : globalInstances) {
 
 3157                 if (globalInstance.getKnownStatus() == null) {
 
 3158                     throw new CentralRepoException(
"EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + 
" has null known status");
 
 3161                 bulkPs.setInt(1, globalInstance.getGlobalSetID());
 
 3162                 bulkPs.setString(2, globalInstance.getMD5Hash());
 
 3163                 bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
 
 3164                 bulkPs.setString(4, globalInstance.getComment());
 
 3168             bulkPs.executeBatch();
 
 3170         } 
catch (SQLException | CentralRepoException ex) {
 
 3173             } 
catch (SQLException ex2) {
 
 3176             throw new CentralRepoException(
"Error inserting bulk artifacts.", ex); 
 
 3178             CentralRepoDbUtil.closeStatement(bulkPs);
 
 3179             CentralRepoDbUtil.closeConnection(conn);
 
 3194     public List<CentralRepoFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) 
throws CentralRepoException, CorrelationAttributeNormalizationException {
 
 3195         String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
 
 3197         Connection conn = connect();
 
 3199         List<CentralRepoFileInstance> globalFileInstances = 
new ArrayList<>();
 
 3200         PreparedStatement preparedStatement1 = null;
 
 3201         ResultSet resultSet = null;
 
 3202         String sql1 = 
"SELECT * FROM %s WHERE value=?";
 
 3205             preparedStatement1 = conn.prepareStatement(String.format(sql1, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
 
 3206             preparedStatement1.setString(1, normalizeValued);
 
 3207             resultSet = preparedStatement1.executeQuery();
 
 3208             while (resultSet.next()) {
 
 3209                 globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
 
 3212         } 
catch (SQLException ex) {
 
 3213             throw new CentralRepoException(
"Error getting reference instances by type and value.", ex); 
 
 3215             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3216             CentralRepoDbUtil.closeStatement(preparedStatement1);
 
 3217             CentralRepoDbUtil.closeConnection(conn);
 
 3220         return globalFileInstances;
 
 3233     public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
 
 3234         if (newType == null) {
 
 3235             throw new CentralRepoException(
"Correlation type is null");
 
 3238         if (-1 == newType.getId()) {
 
 3239             typeId = newCorrelationTypeNotKnownId(newType);
 
 3241             typeId = newCorrelationTypeKnownId(newType);
 
 3244         synchronized (typeCache) {
 
 3245             typeCache.put(newType.getId(), newType);
 
 3260     public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
 
 3261         Connection conn = connect();
 
 3263         PreparedStatement preparedStatement = null;
 
 3264         PreparedStatement preparedStatementQuery = null;
 
 3265         ResultSet resultSet = null;
 
 3270         insertSql = 
"INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
 
 3272         querySql = 
"SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
 
 3275             preparedStatement = conn.prepareStatement(insertSql);
 
 3277             preparedStatement.setString(1, newType.getDisplayName());
 
 3278             preparedStatement.setString(2, newType.getDbTableName());
 
 3279             preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
 
 3280             preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
 
 3282             preparedStatement.executeUpdate();
 
 3284             preparedStatementQuery = conn.prepareStatement(querySql);
 
 3285             preparedStatementQuery.setString(1, newType.getDisplayName());
 
 3286             preparedStatementQuery.setString(2, newType.getDbTableName());
 
 3288             resultSet = preparedStatementQuery.executeQuery();
 
 3289             if (resultSet.next()) {
 
 3290                 CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
 
 3291                 typeId = correlationType.getId();
 
 3293         } 
catch (SQLException ex) {
 
 3294             throw new CentralRepoException(
"Error inserting new correlation type.", ex); 
 
 3296             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3297             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3298             CentralRepoDbUtil.closeStatement(preparedStatementQuery);
 
 3299             CentralRepoDbUtil.closeConnection(conn);
 
 3313     private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
 
 3314         Connection conn = connect();
 
 3316         PreparedStatement preparedStatement = null;
 
 3317         PreparedStatement preparedStatementQuery = null;
 
 3318         ResultSet resultSet = null;
 
 3323         insertSql = 
"INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
 
 3325         querySql = 
"SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
 
 3328             preparedStatement = conn.prepareStatement(insertSql);
 
 3330             preparedStatement.setInt(1, newType.getId());
 
 3331             preparedStatement.setString(2, newType.getDisplayName());
 
 3332             preparedStatement.setString(3, newType.getDbTableName());
 
 3333             preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
 
 3334             preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
 
 3336             preparedStatement.executeUpdate();
 
 3338             preparedStatementQuery = conn.prepareStatement(querySql);
 
 3339             preparedStatementQuery.setString(1, newType.getDisplayName());
 
 3340             preparedStatementQuery.setString(2, newType.getDbTableName());
 
 3342             resultSet = preparedStatementQuery.executeQuery();
 
 3343             if (resultSet.next()) {
 
 3344                 CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
 
 3345                 typeId = correlationType.getId();
 
 3347         } 
catch (SQLException ex) {
 
 3348             throw new CentralRepoException(
"Error inserting new correlation type.", ex); 
 
 3350             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3351             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3352             CentralRepoDbUtil.closeStatement(preparedStatementQuery);
 
 3353             CentralRepoDbUtil.closeConnection(conn);
 
 3359     public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws CentralRepoException {
 
 3361         synchronized (typeCache) {
 
 3362             if (isCRTypeCacheInitialized == 
false) {
 
 3363                 getCorrelationTypesFromCr();
 
 3365             return new ArrayList<>(typeCache.asMap().values());
 
 3379     public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws CentralRepoException {
 
 3380         Connection conn = connect();
 
 3382         List<CorrelationAttributeInstance.Type> aTypes = 
new ArrayList<>();
 
 3383         PreparedStatement preparedStatement = null;
 
 3384         ResultSet resultSet = null;
 
 3385         String sql = 
"SELECT * FROM correlation_types WHERE enabled=1";
 
 3388             preparedStatement = conn.prepareStatement(sql);
 
 3389             resultSet = preparedStatement.executeQuery();
 
 3390             while (resultSet.next()) {
 
 3391                 aTypes.add(getCorrelationTypeFromResultSet(resultSet));
 
 3395         } 
catch (SQLException ex) {
 
 3396             throw new CentralRepoException(
"Error getting enabled correlation types.", ex); 
 
 3398             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3399             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3400             CentralRepoDbUtil.closeConnection(conn);
 
 3414     public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws CentralRepoException {
 
 3415         Connection conn = connect();
 
 3417         List<CorrelationAttributeInstance.Type> aTypes = 
new ArrayList<>();
 
 3418         PreparedStatement preparedStatement = null;
 
 3419         ResultSet resultSet = null;
 
 3420         String sql = 
"SELECT * FROM correlation_types WHERE supported=1";
 
 3423             preparedStatement = conn.prepareStatement(sql);
 
 3424             resultSet = preparedStatement.executeQuery();
 
 3425             while (resultSet.next()) {
 
 3426                 aTypes.add(getCorrelationTypeFromResultSet(resultSet));
 
 3430         } 
catch (SQLException ex) {
 
 3431             throw new CentralRepoException(
"Error getting supported correlation types.", ex); 
 
 3433             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3434             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3435             CentralRepoDbUtil.closeConnection(conn);
 
 3447     public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws CentralRepoException {
 
 3448         Connection conn = connect();
 
 3450         PreparedStatement preparedStatement = null;
 
 3451         String sql = 
"UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
 
 3454             preparedStatement = conn.prepareStatement(sql);
 
 3455             preparedStatement.setString(1, aType.getDisplayName());
 
 3456             preparedStatement.setString(2, aType.getDbTableName());
 
 3457             preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
 
 3458             preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
 
 3459             preparedStatement.setInt(5, aType.getId());
 
 3460             preparedStatement.executeUpdate();
 
 3461             synchronized (typeCache) {
 
 3462                 typeCache.put(aType.getId(), aType);
 
 3464         } 
catch (SQLException ex) {
 
 3465             throw new CentralRepoException(
"Error updating correlation type.", ex); 
 
 3467             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3468             CentralRepoDbUtil.closeConnection(conn);
 
 3483     public CorrelationAttributeInstance.Type getCorrelationTypeById(
int typeId) 
throws CentralRepoException {
 
 3485             synchronized (typeCache) {
 
 3486                 return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
 
 3488         } 
catch (CacheLoader.InvalidCacheLoadException ignored) {
 
 3491         } 
catch (ExecutionException ex) {
 
 3492             throw new CentralRepoException(
"Error getting correlation type", ex);
 
 3505     private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(
int typeId) 
throws CentralRepoException {
 
 3506         Connection conn = connect();
 
 3508         CorrelationAttributeInstance.Type aType;
 
 3509         PreparedStatement preparedStatement = null;
 
 3510         ResultSet resultSet = null;
 
 3511         String sql = 
"SELECT * FROM correlation_types WHERE id=?";
 
 3514             preparedStatement = conn.prepareStatement(sql);
 
 3515             preparedStatement.setInt(1, typeId);
 
 3516             resultSet = preparedStatement.executeQuery();
 
 3517             if (resultSet.next()) {
 
 3518                 aType = getCorrelationTypeFromResultSet(resultSet);
 
 3521                 throw new CentralRepoException(
"Failed to find entry for correlation type ID = " + typeId);
 
 3524         } 
catch (SQLException ex) {
 
 3525             throw new CentralRepoException(
"Error getting correlation type by id.", ex); 
 
 3527             CentralRepoDbUtil.closeResultSet(resultSet);
 
 3528             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 3529             CentralRepoDbUtil.closeConnection(conn);
 
 3539     private void getCorrelationTypesFromCr() throws CentralRepoException {
 
 3542         synchronized (typeCache) {
 
 3543             typeCache.invalidateAll();
 
 3544             isCRTypeCacheInitialized = 
false;
 
 3547         String sql = 
"SELECT * FROM correlation_types";
 
 3548         try (Connection conn = connect();
 
 3549                 PreparedStatement preparedStatement = conn.prepareStatement(sql);
 
 3550                 ResultSet resultSet = preparedStatement.executeQuery();) {
 
 3552             synchronized (typeCache) {
 
 3553                 while (resultSet.next()) {
 
 3554                     CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet);
 
 3555                     typeCache.put(aType.getId(), aType);
 
 3557                 isCRTypeCacheInitialized = 
true;
 
 3559         } 
catch (SQLException ex) {
 
 3560             throw new CentralRepoException(
"Error getting correlation types.", ex); 
 
 3574     private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) 
throws SQLException {
 
 3575         if (null == resultSet) {
 
 3579         CentralRepoOrganization eamOrg = null;
 
 3581         resultSet.getInt(
"org_id");
 
 3582         if (!resultSet.wasNull()) {
 
 3584             eamOrg = 
new CentralRepoOrganization(resultSet.getInt(
"org_id"),
 
 3585                     resultSet.getString(
"org_name"),
 
 3586                     resultSet.getString(
"poc_name"),
 
 3587                     resultSet.getString(
"poc_email"),
 
 3588                     resultSet.getString(
"poc_phone"));
 
 3591         CorrelationCase eamCase = 
new CorrelationCase(resultSet.getInt(
"case_id"), resultSet.getString(
"case_uid"), eamOrg, resultSet.getString(
"case_name"),
 
 3592                 resultSet.getString(
"creation_date"), resultSet.getString(
"case_number"), resultSet.getString(
"examiner_name"),
 
 3593                 resultSet.getString(
"examiner_email"), resultSet.getString(
"examiner_phone"), resultSet.getString(
"notes"));
 
 3598     private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) 
throws SQLException {
 
 3599         if (null == resultSet) {
 
 3603         CorrelationDataSource eamDataSource = 
new CorrelationDataSource(
 
 3604                 resultSet.getInt(
"case_id"),
 
 3605                 resultSet.getInt(
"id"),
 
 3606                 resultSet.getString(
"device_id"),
 
 3607                 resultSet.getString(
"name"),
 
 3608                 resultSet.getLong(
"datasource_obj_id"),
 
 3609                 resultSet.getString(
"md5"),
 
 3610                 resultSet.getString(
"sha1"),
 
 3611                 resultSet.getString(
"sha256")
 
 3614         return eamDataSource;
 
 3617     private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) 
throws CentralRepoException, SQLException {
 
 3618         if (null == resultSet) {
 
 3622         CorrelationAttributeInstance.Type eamArtifactType = 
new CorrelationAttributeInstance.Type(
 
 3623                 resultSet.getInt(
"id"),
 
 3624                 resultSet.getString(
"display_name"),
 
 3625                 resultSet.getString(
"db_table_name"),
 
 3626                 resultSet.getBoolean(
"supported"),
 
 3627                 resultSet.getBoolean(
"enabled")
 
 3630         return eamArtifactType;
 
 3643     private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
 
 3644         if (null == resultSet) {
 
 3648         CentralRepoOrganization eamOrg = 
new CentralRepoOrganization(resultSet.getInt(
"org_id"),
 
 3649                 resultSet.getString(
"org_name"),
 
 3650                 resultSet.getString(
"poc_name"),
 
 3651                 resultSet.getString(
"poc_email"),
 
 3652                 resultSet.getString(
"poc_phone"));
 
 3654         return new CorrelationAttributeInstance(
 
 3656                 resultSet.getString(
"value"),
 
 3657                 resultSet.getInt(
"instance_id"),
 
 3658                 new CorrelationCase(resultSet.getInt(
"id"), resultSet.getString(
"case_uid"), eamOrg, resultSet.getString(
"case_name"),
 
 3659                         resultSet.getString(
"creation_date"), resultSet.getString(
"case_number"), resultSet.getString(
"examiner_name"),
 
 3660                         resultSet.getString(
"examiner_email"), resultSet.getString(
"examiner_phone"), resultSet.getString(
"notes")),
 
 3661                 new CorrelationDataSource(
 
 3662                         resultSet.getInt(
"id"), resultSet.getInt(
"data_source_id"), resultSet.getString(
"device_id"), resultSet.getString(
"name"),
 
 3663                         resultSet.getLong(
"datasource_obj_id"), resultSet.getString(
"md5"), resultSet.getString(
"sha1"), resultSet.getString(
"sha256")),
 
 3664                 resultSet.getString(
"file_path"),
 
 3665                 resultSet.getString(
"comment"),
 
 3666                 TskData.FileKnown.valueOf(resultSet.getByte(
"known_status")),
 
 3667                 resultSet.getLong(
"file_obj_id"));
 
 3670     private CentralRepoOrganization getEamOrganizationFromResultSet(ResultSet resultSet) 
throws SQLException {
 
 3671         if (null == resultSet) {
 
 3675         return new CentralRepoOrganization(
 
 3676                 resultSet.getInt(
"id"),
 
 3677                 resultSet.getString(
"org_name"),
 
 3678                 resultSet.getString(
"poc_name"),
 
 3679                 resultSet.getString(
"poc_email"),
 
 3680                 resultSet.getString(
"poc_phone")
 
 3684     private CentralRepoFileSet getEamGlobalSetFromResultSet(ResultSet resultSet) 
throws SQLException, CentralRepoException {
 
 3685         if (null == resultSet) {
 
 3689         return new CentralRepoFileSet(
 
 3690                 resultSet.getInt(
"id"),
 
 3691                 resultSet.getInt(
"org_id"),
 
 3692                 resultSet.getString(
"set_name"),
 
 3693                 resultSet.getString(
"version"),
 
 3694                 TskData.FileKnown.valueOf(resultSet.getByte(
"known_status")),
 
 3695                 resultSet.getBoolean(
"read_only"),
 
 3696                 CentralRepository.getInstance().getCorrelationTypeById(resultSet.getInt(
"type")),
 
 3697                 LocalDate.parse(resultSet.getString(
"import_date"))
 
 3701     private CentralRepoFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) 
throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
 
 3702         if (null == resultSet) {
 
 3706         return new CentralRepoFileInstance(
 
 3707                 resultSet.getInt(
"id"),
 
 3708                 resultSet.getInt(
"reference_set_id"),
 
 3709                 resultSet.getString(
"value"),
 
 3710                 TskData.FileKnown.valueOf(resultSet.getByte(
"known_status")),
 
 3711                 resultSet.getString(
"comment")
 
 3715     private String getPlatformSpecificInsertSQL(String sql) 
throws CentralRepoException {
 
 3717         switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
 
 3719                 return "INSERT " + sql + 
" ON CONFLICT DO NOTHING"; 
 
 3721                 return "INSERT OR IGNORE " + sql;
 
 3724                 throw new CentralRepoException(
"Unknown Central Repo DB platform" + CentralRepoDbManager.getSavedDbChoice().getDbPlatform());
 
 3738     abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) 
throws SQLException;
 
 3745     @Messages({
"AbstractSqlEamDb.upgradeSchema.incompatible=The selected Central Repository is not compatible with the current version of the application, please upgrade the application if you wish to use this Central Repository.",
 
 3746         "# {0} - minorVersion",
 
 3747         "AbstractSqlEamDb.badMinorSchema.message=Bad value for schema minor version ({0}) - database is corrupt.",
 
 3748         "AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository.",
 
 3749         "# {0} - majorVersion",
 
 3750         "AbstractSqlEamDb.badMajorSchema.message=Bad value for schema version ({0}) - database is corrupt.",
 
 3751         "AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository.",
 
 3752         "# {0} - platformName",
 
 3753         "AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform \"{0}\" can not be upgraded."})
 
 3755     public void upgradeSchema() throws CentralRepoException, SQLException, IncompatibleCentralRepoException {
 
 3757         ResultSet resultSet = null;
 
 3758         Statement statement = null;
 
 3759         PreparedStatement preparedStatement = null;
 
 3760         Connection conn = null;
 
 3761         CentralRepoPlatforms selectedPlatform = null;
 
 3764             conn = connect(
false);
 
 3765             conn.setAutoCommit(
false);
 
 3766             statement = conn.createStatement();
 
 3767             selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
 
 3768             int minorVersion = 0;
 
 3769             String minorVersionStr = null;
 
 3770             resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + 
"'");
 
 3771             if (resultSet.next()) {
 
 3772                 minorVersionStr = resultSet.getString(
"value");
 
 3774                     minorVersion = Integer.parseInt(minorVersionStr);
 
 3775                 } 
catch (NumberFormatException ex) {
 
 3776                     throw new CentralRepoException(
"Bad value for schema minor version (" + minorVersionStr + 
") - database is corrupt", Bundle.AbstractSqlEamDb_badMinorSchema_message(minorVersionStr), ex);
 
 3779                 throw new CentralRepoException(
"Failed to read schema minor version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMinorVersion_message());
 
 3782             int majorVersion = 0;
 
 3783             String majorVersionStr = null;
 
 3784             resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + 
"'");
 
 3785             if (resultSet.next()) {
 
 3786                 majorVersionStr = resultSet.getString(
"value");
 
 3788                     majorVersion = Integer.parseInt(majorVersionStr);
 
 3789                 } 
catch (NumberFormatException ex) {
 
 3790                     throw new CentralRepoException(
"Bad value for schema version (" + majorVersionStr + 
") - database is corrupt", Bundle.AbstractSqlEamDb_badMajorSchema_message(majorVersionStr), ex);
 
 3793                 throw new CentralRepoException(
"Failed to read schema major version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMajorVersion_message());
 
 3804             CaseDbSchemaVersionNumber dbSchemaVersion = 
new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
 
 3809             if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
 
 3810                 throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
 
 3812             if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
 
 3813                 logger.log(Level.INFO, 
"Central Repository is up to date");
 
 3816             if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
 
 3817                 logger.log(Level.INFO, 
"Central Repository is of newer version than software creates");
 
 3824             if (dbSchemaVersion.compareTo(
new CaseDbSchemaVersionNumber(1, 1)) < 0) {
 
 3825                 statement.execute(
"ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); 
 
 3826                 statement.execute(
"ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); 
 
 3827                 statement.execute(
"ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); 
 
 3832                 CentralRepoDbUtil.insertDefaultOrganization(conn);
 
 3838             if (dbSchemaVersion.compareTo(
new CaseDbSchemaVersionNumber(1, 2)) < 0) {
 
 3839                 final String addIntegerColumnTemplate = 
"ALTER TABLE %s ADD COLUMN %s INTEGER;";  
 
 3841                 final String addSsidTableTemplate = RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform);
 
 3842                 final String addCaseIdIndexTemplate = RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate();
 
 3843                 final String addDataSourceIdIndexTemplate = RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate();
 
 3844                 final String addValueIndexTemplate = RdbmsCentralRepoFactory.getAddValueIndexTemplate();
 
 3845                 final String addKnownStatusIndexTemplate = RdbmsCentralRepoFactory.getAddKnownStatusIndexTemplate();
 
 3846                 final String addObjectIdIndexTemplate = RdbmsCentralRepoFactory.getAddObjectIdIndexTemplate();
 
 3848                 final String addAttributeSql;
 
 3850                 switch (selectedPlatform) {
 
 3852                         addAttributeSql = 
"INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();  
 
 3855                         addAttributeSql = 
"INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)";  
 
 3858                         throw new CentralRepoException(
"Currently selected database platform \"" + selectedPlatform.name() + 
"\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
 
 3861                 final String dataSourcesTableName = 
"data_sources";
 
 3862                 final String dataSourceObjectIdColumnName = 
"datasource_obj_id";
 
 3863                 if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
 
 3864                     statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); 
 
 3866                 final String dataSourceObjectIdIndexTemplate = 
"CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
 
 3867                 statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
 
 3868                 List<String> instaceTablesToAdd = 
new ArrayList<>();
 
 3870                 final String wirelessNetworksDbTableName = 
"wireless_networks";
 
 3871                 instaceTablesToAdd.add(wirelessNetworksDbTableName + 
"_instances");
 
 3872                 final String macAddressDbTableName = 
"mac_address";
 
 3873                 instaceTablesToAdd.add(macAddressDbTableName + 
"_instances");
 
 3874                 final String imeiNumberDbTableName = 
"imei_number";
 
 3875                 instaceTablesToAdd.add(imeiNumberDbTableName + 
"_instances");
 
 3876                 final String iccidNumberDbTableName = 
"iccid_number";
 
 3877                 instaceTablesToAdd.add(iccidNumberDbTableName + 
"_instances");
 
 3878                 final String imsiNumberDbTableName = 
"imsi_number";
 
 3879                 instaceTablesToAdd.add(imsiNumberDbTableName + 
"_instances");
 
 3882                 preparedStatement = conn.prepareStatement(addAttributeSql);
 
 3883                 preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
 
 3884                 preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
 
 3885                 preparedStatement.setString(3, wirelessNetworksDbTableName);
 
 3886                 preparedStatement.setInt(4, 1);
 
 3887                 preparedStatement.setInt(5, 1);
 
 3888                 preparedStatement.execute();
 
 3891                 preparedStatement = conn.prepareStatement(addAttributeSql);
 
 3892                 preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
 
 3893                 preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
 
 3894                 preparedStatement.setString(3, macAddressDbTableName);
 
 3895                 preparedStatement.setInt(4, 1);
 
 3896                 preparedStatement.setInt(5, 1);
 
 3897                 preparedStatement.execute();
 
 3900                 preparedStatement = conn.prepareStatement(addAttributeSql);
 
 3901                 preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
 
 3902                 preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
 
 3903                 preparedStatement.setString(3, imeiNumberDbTableName);
 
 3904                 preparedStatement.setInt(4, 1);
 
 3905                 preparedStatement.setInt(5, 1);
 
 3906                 preparedStatement.execute();
 
 3909                 preparedStatement = conn.prepareStatement(addAttributeSql);
 
 3910                 preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
 
 3911                 preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
 
 3912                 preparedStatement.setString(3, imsiNumberDbTableName);
 
 3913                 preparedStatement.setInt(4, 1);
 
 3914                 preparedStatement.setInt(5, 1);
 
 3915                 preparedStatement.execute();
 
 3918                 preparedStatement = conn.prepareStatement(addAttributeSql);
 
 3919                 preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
 
 3920                 preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
 
 3921                 preparedStatement.setString(3, iccidNumberDbTableName);
 
 3922                 preparedStatement.setInt(4, 1);
 
 3923                 preparedStatement.setInt(5, 1);
 
 3924                 preparedStatement.execute();
 
 3927                 for (String tableName : instaceTablesToAdd) {
 
 3928                     statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
 
 3929                     statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
 
 3930                     statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
 
 3931                     statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
 
 3932                     statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
 
 3936                 String instance_type_dbname;
 
 3937                 final String objectIdColumnName = 
"file_obj_id";
 
 3938                 for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
 
 3939                     instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
 
 3940                     if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
 
 3941                         statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); 
 
 3943                     statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
 
 3949                 if (!doesColumnExist(conn, dataSourcesTableName, 
"md5")) {
 
 3950                     statement.execute(
"ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
 
 3952                 if (!doesColumnExist(conn, dataSourcesTableName, 
"sha1")) {
 
 3953                     statement.execute(
"ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
 
 3955                 if (!doesColumnExist(conn, dataSourcesTableName, 
"sha256")) {
 
 3956                     statement.execute(
"ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
 
 3967                 String creationMajorVer;
 
 3968                 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + 
"'");
 
 3969                 if (resultSet.next()) {
 
 3970                     creationMajorVer = resultSet.getString(
"value");
 
 3972                     creationMajorVer = 
"0";
 
 3974                 String creationMinorVer;
 
 3975                 resultSet = statement.executeQuery(
"SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + 
"'");
 
 3976                 if (resultSet.next()) {
 
 3977                     creationMinorVer = resultSet.getString(
"value");
 
 3979                     creationMinorVer = 
"0";
 
 3981                 statement.execute(
"DROP TABLE db_info");
 
 3982                 if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
 
 3983                     statement.execute(
"CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
 
 3985                     statement.execute(
"CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
 
 3987                 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + 
"','" + majorVersionStr + 
"')");
 
 3988                 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + 
"','" + minorVersionStr + 
"')");
 
 3989                 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + 
"','" + creationMajorVer + 
"')");
 
 3990                 statement.execute(
"INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + 
"','" + creationMinorVer + 
"')");
 
 3995             if (dbSchemaVersion.compareTo(
new CaseDbSchemaVersionNumber(1, 3)) < 0) {
 
 3996                 switch (selectedPlatform) {
 
 3998                         statement.execute(
"ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
 
 4000                         statement.execute(
"ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
 
 4004                         statement.execute(
"DROP INDEX IF EXISTS data_sources_name");
 
 4005                         statement.execute(
"DROP INDEX IF EXISTS data_sources_object_id");
 
 4006                         statement.execute(
"ALTER TABLE data_sources RENAME TO old_data_sources");
 
 4008                         statement.execute(
"CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL," 
 4009                                 + 
"case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer," 
 4010                                 + 
"md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL," 
 4011                                 + 
"foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL," 
 4012                                 + 
"CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
 
 4013                         statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesNameIndexStatement());
 
 4014                         statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesObjectIdIndexStatement());
 
 4015                         statement.execute(
"INSERT INTO data_sources SELECT * FROM old_data_sources");
 
 4016                         statement.execute(
"DROP TABLE old_data_sources");
 
 4019                         throw new CentralRepoException(
"Currently selected database platform \"" + selectedPlatform.name() + 
"\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
 
 4024             (
new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
 
 4027             (
new CentralRepoDbUpgrader14To15()).upgradeSchema(dbSchemaVersion, conn);
 
 4030             (
new CentralRepoDbUpgrader15To16()).upgradeSchema(dbSchemaVersion, conn);
 
 4032             updateSchemaVersion(conn);
 
 4034             logger.log(Level.INFO, String.format(
"Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
 
 4035         } 
catch (SQLException | CentralRepoException ex) {
 
 4040             } 
catch (SQLException ex2) {
 
 4041                 logger.log(Level.SEVERE, String.format(
"Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
 
 4045             CentralRepoDbUtil.closeResultSet(resultSet);
 
 4046             CentralRepoDbUtil.closeStatement(preparedStatement);
 
 4047             CentralRepoDbUtil.closeStatement(statement);
 
 4048             CentralRepoDbUtil.closeConnection(conn);
 
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)
 
CentralRepoAccount getOrCreateAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)