19 package org.sleuthkit.autopsy.centralrepository.datamodel;
 
   21 import java.sql.Connection;
 
   22 import java.sql.ResultSet;
 
   23 import java.sql.SQLException;
 
   24 import java.sql.Statement;
 
   25 import java.util.Arrays;
 
   26 import java.util.List;
 
   28 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
   29 import java.util.logging.Level;
 
   30 import org.apache.commons.dbcp2.BasicDataSource;
 
   31 import org.openide.util.NbBundle.Messages;
 
   42 final class SqliteEamDb 
extends AbstractSqlEamDb {
 
   44     private final static Logger LOGGER = Logger.getLogger(SqliteEamDb.class.getName());
 
   46     private static SqliteEamDb instance;
 
   48     private BasicDataSource connectionPool = null;
 
   50     private final SqliteEamDbSettings dbSettings;
 
   54     private final ReentrantReadWriteLock rwLock = 
new ReentrantReadWriteLock(
true);
 
   64     public synchronized static SqliteEamDb getInstance() throws EamDbException {
 
   65         if (instance == null) {
 
   66             instance = 
new SqliteEamDb();
 
   78     private SqliteEamDb() throws EamDbException {
 
   79         dbSettings = 
new SqliteEamDbSettings();
 
   80         bulkArtifactsThreshold = dbSettings.getBulkThreshold();
 
   84     public void shutdownConnections() throws EamDbException {
 
   87                 if (null != connectionPool) {
 
   88                     connectionPool.close();
 
   89                     connectionPool = null; 
 
   93         } 
catch (SQLException ex) {
 
   94             throw new EamDbException(
"Failed to close existing database connections.", ex); 
 
   99     public void updateSettings() {
 
  100         synchronized (
this) {
 
  101             dbSettings.loadSettings();
 
  102             bulkArtifactsThreshold = dbSettings.getBulkThreshold();
 
  107     public void saveSettings() {
 
  108         synchronized (
this) {
 
  109             dbSettings.saveSettings();
 
  114     public void reset() throws EamDbException {
 
  116             acquireExclusiveLock();
 
  118             Connection conn = connect();
 
  122                 Statement dropContent = conn.createStatement();
 
  123                 dropContent.executeUpdate(
"DELETE FROM organizations");
 
  124                 dropContent.executeUpdate(
"DELETE FROM cases");
 
  125                 dropContent.executeUpdate(
"DELETE FROM data_sources");
 
  126                 dropContent.executeUpdate(
"DELETE FROM reference_sets");
 
  127                 dropContent.executeUpdate(
"DELETE FROM artifact_types");
 
  128                 dropContent.executeUpdate(
"DELETE FROM db_info");
 
  130                 String instancesTemplate = 
"DELETE FROM %s_instances";
 
  131                 String referencesTemplate = 
"DELETE FROM global_files";
 
  132                 for (CorrelationAttributeInstance.Type type : defaultCorrelationTypes) {
 
  133                     dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName()));
 
  135                     if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
 
  136                         dropContent.executeUpdate(String.format(referencesTemplate, type.getDbTableName()));
 
  140                 dropContent.executeUpdate(
"VACUUM");
 
  141             } 
catch (SQLException ex) {
 
  142                 LOGGER.log(Level.WARNING, 
"Failed to reset database.", ex);
 
  144                 EamDbUtil.closeConnection(conn);
 
  147             dbSettings.insertDefaultDatabaseContent();
 
  149             releaseExclusiveLock();
 
  157     @Messages({
"SqliteEamDb.databaseMissing.message=Central repository database missing"})
 
  158     private void setupConnectionPool(
boolean foreignKeysEnabled) 
throws EamDbException {
 
  160         if (dbSettings.dbFileExists() == 
false) {
 
  161             throw new EamDbException(Bundle.SqliteEamDb_databaseMissing_message());
 
  164         connectionPool = 
new BasicDataSource();
 
  165         connectionPool.setDriverClassName(dbSettings.getDriver());
 
  166         connectionPool.setUrl(dbSettings.getConnectionURL());
 
  169         connectionPool.setInitialSize(50);
 
  170         connectionPool.setMaxTotal(-1);
 
  171         connectionPool.setMaxIdle(-1);
 
  172         connectionPool.setMaxWaitMillis(1000);
 
  173         connectionPool.setValidationQuery(dbSettings.getValidationQuery());
 
  174         if (foreignKeysEnabled) {
 
  175             connectionPool.setConnectionInitSqls(Arrays.asList(
"PRAGMA foreign_keys = ON"));
 
  177             connectionPool.setConnectionInitSqls(Arrays.asList(
"PRAGMA foreign_keys = OFF"));
 
  191     @Messages({
"SqliteEamDb.connectionFailedMessage.message=Error getting connection to database.",
 
  192         "SqliteEamDb.centralRepositoryDisabled.message=Central Repository module is not enabled."})
 
  194     protected Connection connect(
boolean foreignKeys) 
throws EamDbException {
 
  195         synchronized (
this) {
 
  196             if (!EamDb.isEnabled()) {
 
  197                 throw new EamDbException(Bundle.SqliteEamDb_centralRepositoryDisabled_message()); 
 
  199             if (connectionPool == null) {
 
  200                 setupConnectionPool(foreignKeys);
 
  203                 return connectionPool.getConnection();
 
  204             } 
catch (SQLException ex) {
 
  205                 throw new EamDbException(Bundle.SqliteEamDb_connectionFailedMessage_message(), ex); 
 
  219     protected Connection connect() throws EamDbException {
 
  220         return connect(
true);
 
  224     protected String getConflictClause() {
 
  238     public void newDbInfo(String name, String value) 
throws EamDbException {
 
  240             acquireExclusiveLock();
 
  241             super.newDbInfo(name, value);
 
  243             releaseExclusiveLock();
 
  257     public String getDbInfo(String name) 
throws EamDbException {
 
  260             return super.getDbInfo(name);
 
  275     public void updateDbInfo(String name, String value) 
throws EamDbException {
 
  277             acquireExclusiveLock();
 
  278             super.updateDbInfo(name, value);
 
  280             releaseExclusiveLock();
 
  290     public CorrelationCase newCase(Case autopsyCase) 
throws EamDbException {
 
  292             acquireExclusiveLock();
 
  293             return super.newCase(autopsyCase);
 
  295             releaseExclusiveLock();
 
  300     public void addDataSourceObjectId(
int rowId, 
long dataSourceObjectId) 
throws EamDbException {
 
  302             acquireExclusiveLock();
 
  303             super.addDataSourceObjectId(rowId, dataSourceObjectId);
 
  305             releaseExclusiveLock();
 
  317     public CorrelationCase newCase(CorrelationCase eamCase) 
throws EamDbException {
 
  319             acquireExclusiveLock();
 
  320             return super.newCase(eamCase);
 
  322             releaseExclusiveLock();
 
  332     public void updateCase(CorrelationCase eamCase) 
throws EamDbException {
 
  334             acquireExclusiveLock();
 
  335             super.updateCase(eamCase);
 
  337             releaseExclusiveLock();
 
  349     public CorrelationCase getCaseByUUID(String caseUUID) 
throws EamDbException {
 
  352             return super.getCaseByUUID(caseUUID);
 
  366     public CorrelationCase getCaseById(
int caseId) 
throws EamDbException {
 
  369             return super.getCaseById(caseId);
 
  382     public List<CorrelationCase> getCases() throws EamDbException {
 
  385             return super.getCases();
 
  397     public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) 
throws EamDbException {
 
  399             acquireExclusiveLock();
 
  400             return super.newDataSource(eamDataSource);
 
  402             releaseExclusiveLock();
 
  416     public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long caseDbDataSourceId) 
throws EamDbException {
 
  419             return super.getDataSource(correlationCase, caseDbDataSourceId);
 
  435     public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, 
int dataSourceId) 
throws EamDbException {
 
  438             return super.getDataSourceById(correlationCase, dataSourceId);
 
  450     public List<CorrelationDataSource> getDataSources() throws EamDbException {
 
  453             return super.getDataSources();
 
  468     public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) 
throws EamDbException {
 
  470             acquireExclusiveLock();
 
  471             super.updateDataSourceName(eamDataSource, newName);
 
  473             releaseExclusiveLock();
 
  483     public void updateDataSourceMd5Hash(CorrelationDataSource eamDataSource) 
throws EamDbException {
 
  485             acquireExclusiveLock();
 
  486             super.updateDataSourceMd5Hash(eamDataSource);
 
  488             releaseExclusiveLock();
 
  498     public void updateDataSourceSha1Hash(CorrelationDataSource eamDataSource) 
throws EamDbException {
 
  500             acquireExclusiveLock();
 
  501             super.updateDataSourceSha1Hash(eamDataSource);
 
  503             releaseExclusiveLock();
 
  514     public void updateDataSourceSha256Hash(CorrelationDataSource eamDataSource) 
throws EamDbException {
 
  516             acquireExclusiveLock();
 
  517             super.updateDataSourceSha256Hash(eamDataSource);
 
  519             releaseExclusiveLock();
 
  530     public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) 
throws EamDbException {
 
  532             acquireExclusiveLock();
 
  533             super.addArtifactInstance(eamArtifact);
 
  535             releaseExclusiveLock();
 
  540     public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  543             return super.getArtifactInstancesByTypeValue(aType, value);
 
  550     public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  553             return super.getArtifactInstancesByTypeValues(aType, values);
 
  560     public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  563             return super.getArtifactInstancesByTypeValuesAndCases(aType, values, caseIds);
 
  582     public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  585             return super.getCountArtifactInstancesByTypeValue(aType, value);
 
  592     public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  595             return super.getFrequencyPercentage(corAttr);
 
  614     public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  617             return super.getCountUniqueCaseDataSourceTuplesHavingTypeValue(aType, value);
 
  624     public Long getCountUniqueDataSources() throws EamDbException {
 
  627             return super.getCountUniqueDataSources();
 
  645     public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) 
throws EamDbException {
 
  648             return super.getCountArtifactInstancesByCaseDataSource(correlationDataSource);
 
  659     public void commitAttributeInstancesBulk() throws EamDbException {
 
  661             acquireExclusiveLock();
 
  662             super.commitAttributeInstancesBulk();
 
  664             releaseExclusiveLock();
 
  672     public void bulkInsertCases(List<CorrelationCase> cases) 
throws EamDbException {
 
  674             acquireExclusiveLock();
 
  675             super.bulkInsertCases(cases);
 
  677             releaseExclusiveLock();
 
  692     public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws EamDbException {
 
  694             acquireExclusiveLock();
 
  695             super.setAttributeInstanceKnownStatus(eamArtifact, knownStatus);
 
  697             releaseExclusiveLock();
 
  710     public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  713             return super.getCountArtifactInstancesKnownBad(aType, value);
 
  732     public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  735             return super.getListCasesHavingArtifactInstancesKnownBad(aType, value);
 
  749     public void deleteReferenceSet(
int referenceSetID) 
throws EamDbException {
 
  751             acquireExclusiveLock();
 
  752             super.deleteReferenceSet(referenceSetID);
 
  754             releaseExclusiveLock();
 
  768     public boolean isValueInReferenceSet(String value, 
int referenceSetID, 
int correlationTypeID) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  771             return super.isValueInReferenceSet(value, referenceSetID, correlationTypeID);
 
  786     public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) 
throws EamDbException {
 
  789             super.processInstanceTable(type, instanceTableCallback);
 
  804     public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) 
throws EamDbException {
 
  807             super.processInstanceTableWhere(type, whereClause, instanceTableCallback);
 
  826     public boolean referenceSetExists(String referenceSetName, String version) 
throws EamDbException {
 
  829             return super.referenceSetExists(referenceSetName, version);
 
  844     public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
  847             return super.isArtifactKnownBadByReference(aType, value);
 
  863     public EamOrganization newOrganization(EamOrganization eamOrg) 
throws EamDbException {
 
  865             acquireExclusiveLock();
 
  866             return super.newOrganization(eamOrg);
 
  868             releaseExclusiveLock();
 
  880     public List<EamOrganization> getOrganizations() throws EamDbException {
 
  883             return super.getOrganizations();
 
  899     public EamOrganization getOrganizationByID(
int orgID) 
throws EamDbException {
 
  902             return super.getOrganizationByID(orgID);
 
  909     public void updateOrganization(EamOrganization updatedOrganization) 
throws EamDbException {
 
  911             acquireExclusiveLock();
 
  912             super.updateOrganization(updatedOrganization);
 
  914             releaseExclusiveLock();
 
  919     public void deleteOrganization(EamOrganization organizationToDelete) 
throws EamDbException {
 
  921             acquireExclusiveLock();
 
  922             super.deleteOrganization(organizationToDelete);
 
  924             releaseExclusiveLock();
 
  938     public int newReferenceSet(EamGlobalSet eamGlobalSet) 
throws EamDbException {
 
  940             acquireExclusiveLock();
 
  941             return super.newReferenceSet(eamGlobalSet);
 
  943             releaseExclusiveLock();
 
  957     public EamGlobalSet getReferenceSetByID(
int referenceSetID) 
throws EamDbException {
 
  960             return super.getReferenceSetByID(referenceSetID);
 
  976     public List<EamGlobalSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws EamDbException {
 
  979             return super.getAllReferenceSets(correlationType);
 
  995     public void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws EamDbException {
 
  997             acquireExclusiveLock();
 
  998             super.addReferenceInstance(eamGlobalFileInstance, correlationType);
 
 1000             releaseExclusiveLock();
 
 1010     public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws EamDbException {
 
 1012             acquireExclusiveLock();
 
 1013             super.bulkInsertReferenceTypeEntries(globalInstances, contentType);
 
 1015             releaseExclusiveLock();
 
 1030     public List<EamGlobalFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) 
throws EamDbException, CorrelationAttributeNormalizationException {
 
 1032             acquireSharedLock();
 
 1033             return super.getReferenceInstancesByTypeValue(aType, aValue);
 
 1035             releaseSharedLock();
 
 1049     public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws EamDbException {
 
 1051             acquireExclusiveLock();
 
 1052             return super.newCorrelationType(newType);
 
 1054             releaseExclusiveLock();
 
 1068     public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws EamDbException {
 
 1070             acquireSharedLock();
 
 1071             return super.getDefinedCorrelationTypes();
 
 1073             releaseSharedLock();
 
 1087     public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws EamDbException {
 
 1089             acquireSharedLock();
 
 1090             return super.getEnabledCorrelationTypes();
 
 1092             releaseSharedLock();
 
 1106     public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws EamDbException {
 
 1108             acquireSharedLock();
 
 1109             return super.getSupportedCorrelationTypes();
 
 1111             releaseSharedLock();
 
 1123     public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws EamDbException {
 
 1125             acquireExclusiveLock();
 
 1126             super.updateCorrelationType(aType);
 
 1128             releaseExclusiveLock();
 
 1142     public CorrelationAttributeInstance.Type getCorrelationTypeById(
int typeId) 
throws EamDbException {
 
 1144             acquireSharedLock();
 
 1145             return super.getCorrelationTypeById(typeId);
 
 1147             releaseSharedLock();
 
 1157     public void upgradeSchema() throws EamDbException, SQLException, IncompatibleCentralRepoException {
 
 1159             acquireExclusiveLock();
 
 1160             super.upgradeSchema();
 
 1162             releaseExclusiveLock();
 
 1178     public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException {
 
 1188     private void acquireExclusiveLock() {
 
 1189         rwLock.writeLock().lock();
 
 1197     private void releaseExclusiveLock() {
 
 1198         rwLock.writeLock().unlock();
 
 1206     private void acquireSharedLock() {
 
 1207         rwLock.readLock().lock();
 
 1215     private void releaseSharedLock() {
 
 1216         rwLock.readLock().unlock();
 
 1220     boolean doesColumnExist(Connection conn, String tableName, String columnName) 
throws SQLException {
 
 1221         final String tableInfoQueryTemplate = 
"PRAGMA table_info(%s)";  
 
 1222         ResultSet resultSet = null;
 
 1223         Statement statement = null;
 
 1224         boolean columnExists = 
false;
 
 1226             statement = conn.createStatement();
 
 1227             resultSet = statement.executeQuery(String.format(tableInfoQueryTemplate, tableName));
 
 1228             while (resultSet.next()) {
 
 1230                 if (resultSet.getString(2).equals(columnName)) {
 
 1231                     columnExists = 
true;
 
 1236             EamDbUtil.closeResultSet(resultSet);
 
 1237             EamDbUtil.closeStatement(statement);
 
 1239         return columnExists;