Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
PostgresCentralRepo.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-2018 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.centralrepository.datamodel;
20 
21 import java.sql.Connection;
22 import java.sql.ResultSet;
23 import java.sql.SQLException;
24 import java.sql.Statement;
25 import java.util.concurrent.TimeUnit;
26 import java.util.logging.Level;
27 import org.apache.commons.dbcp2.BasicDataSource;
28 import org.openide.util.NbBundle.Messages;
32 
36 final class PostgresCentralRepo extends RdbmsCentralRepo {
37 
38  private final static Logger LOGGER = Logger.getLogger(PostgresCentralRepo.class.getName());
39 
40  private final static String CONFLICT_CLAUSE = "ON CONFLICT DO NOTHING";
41 
42  private static PostgresCentralRepo instance;
43 
44  private static final int CONN_POOL_SIZE = 10;
45  private BasicDataSource connectionPool = null;
46 
47  private final PostgresCentralRepoSettings dbSettings;
48 
57  public synchronized static PostgresCentralRepo getInstance() throws CentralRepoException {
58  if (instance == null) {
59  instance = new PostgresCentralRepo();
60  }
61 
62  return instance;
63  }
64 
71  private PostgresCentralRepo() throws CentralRepoException {
72  dbSettings = new PostgresCentralRepoSettings();
73  bulkArtifactsThreshold = dbSettings.getBulkThreshold();
74  }
75 
76  @Override
77  public void shutdownConnections() throws CentralRepoException {
78  try {
79  synchronized (this) {
80  if (connectionPool != null) {
81  connectionPool.close();
82  connectionPool = null; // force it to be re-created on next connect()
83  }
84  clearCaches();
85  }
86  } catch (SQLException ex) {
87  throw new CentralRepoException("Failed to close existing database connections.", ex); // NON-NLS
88  }
89  }
90 
91  @Override
92  public void updateSettings() {
93  synchronized (this) {
94  dbSettings.loadSettings();
95  bulkArtifactsThreshold = dbSettings.getBulkThreshold();
96  }
97  }
98 
99  @Override
100  public void saveSettings() {
101  synchronized (this) {
102  dbSettings.saveSettings();
103  }
104  }
105 
106  @Override
107  public void reset() throws CentralRepoException {
108  Connection conn = connect();
109 
110  try {
111  Statement dropContent = conn.createStatement();
112  dropContent.executeUpdate("TRUNCATE TABLE organizations RESTART IDENTITY CASCADE");
113  dropContent.executeUpdate("TRUNCATE TABLE cases RESTART IDENTITY CASCADE");
114  dropContent.executeUpdate("TRUNCATE TABLE data_sources RESTART IDENTITY CASCADE");
115  dropContent.executeUpdate("TRUNCATE TABLE reference_sets RESTART IDENTITY CASCADE");
116  dropContent.executeUpdate("TRUNCATE TABLE correlation_types RESTART IDENTITY CASCADE");
117  dropContent.executeUpdate("TRUNCATE TABLE db_info RESTART IDENTITY CASCADE");
118 
119  String instancesTemplate = "TRUNCATE TABLE %s_instances RESTART IDENTITY CASCADE";
120  String referencesTemplate = "TRUNCATE TABLE reference_%s RESTART IDENTITY CASCADE";
121  for (CorrelationAttributeInstance.Type type : defaultCorrelationTypes) {
122  dropContent.executeUpdate(String.format(instancesTemplate, type.getDbTableName()));
123  // FUTURE: support other reference types
124  if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
125  dropContent.executeUpdate(String.format(referencesTemplate, type.getDbTableName()));
126  }
127  }
128  } catch (SQLException ex) {
129  LOGGER.log(Level.WARNING, "Failed to reset database.", ex);
130  } finally {
131  CentralRepoDbUtil.closeConnection(conn);
132  }
133 
134 
135  RdbmsCentralRepoFactory centralRepoSchemaFactory = new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettings);
136  centralRepoSchemaFactory.insertDefaultDatabaseContent();
137  }
138 
143  private void setupConnectionPool() throws CentralRepoException {
144  connectionPool = new BasicDataSource();
145  connectionPool.setUsername(dbSettings.getUserName());
146  connectionPool.setPassword(dbSettings.getPassword());
147  connectionPool.setDriverClassName(dbSettings.getDriver());
148 
149  StringBuilder connectionURL = new StringBuilder();
150  connectionURL.append(dbSettings.getJDBCBaseURI());
151  connectionURL.append(dbSettings.getHost());
152  connectionURL.append(":");
153  connectionURL.append(dbSettings.getPort());
154  connectionURL.append("/");
155  connectionURL.append(dbSettings.getDbName());
156 
157  connectionPool.setUrl(connectionURL.toString());
158  connectionPool.setUsername(dbSettings.getUserName());
159  connectionPool.setPassword(dbSettings.getPassword());
160 
161  // tweak pool configuration
162  connectionPool.setInitialSize(5); // start with 5 connections
163  connectionPool.setMaxIdle(CONN_POOL_SIZE); // max of 10 idle connections
164  connectionPool.setValidationQuery(dbSettings.getValidationQuery());
165  }
166 
176  @Override
177  protected Connection connect(boolean foreignKeys) throws CentralRepoException {
178  //foreignKeys boolean is ignored for postgres
179  return connect();
180  }
181 
189  @Messages({"PostgresEamDb.centralRepoDisabled.message=Central Repository module is not enabled.",
190  "PostgresEamDb.connectionFailed.message=Error getting connection to database."})
191  @Override
192  protected Connection connect() throws CentralRepoException {
193  synchronized (this) {
194  if (!CentralRepository.isEnabled()) {
195  throw new CentralRepoException("Central Repository module is not enabled", Bundle.PostgresEamDb_centralRepoDisabled_message()); // NON-NLS
196  }
197 
198  if (connectionPool == null) {
199  setupConnectionPool();
200  }
201  try {
202  return connectionPool.getConnection();
203  } catch (SQLException ex) {
204  throw new CentralRepoException("Error getting connection from connection pool.", Bundle.PostgresEamDb_connectionFailed_message(), ex); // NON-NLS
205  }
206  }
207  }
208 
209  @Override
210  protected String getConflictClause() {
211  return CONFLICT_CLAUSE;
212  }
213 
214  @Override
215  protected Connection getEphemeralConnection() {
216  return this.dbSettings.getEphemeralConnection(false);
217  }
229  @Override
230  @Messages({"PostgresEamDb.multiUserLockError.message=Error acquiring database lock"})
231  public CoordinationService.Lock getExclusiveMultiUserDbLock() throws CentralRepoException {
232  try {
233  // First check if multi user mode is enabled - if not there's no point trying to get a lock
234  if (!UserPreferences.getIsMultiUserModeEnabled()) {
235  return null;
236  }
237 
238  String databaseNodeName = dbSettings.getHost() + "_" + dbSettings.getDbName();
239  CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.CENTRAL_REPO, databaseNodeName, 5, TimeUnit.MINUTES);
240 
241  if (lock != null) {
242  return lock;
243  }
244  throw new CentralRepoException("Error acquiring database lock", Bundle.PostgresEamDb_multiUserLockError_message());
245  } catch (InterruptedException ex) {
246  throw new CentralRepoException("Error acquiring database lock", Bundle.PostgresEamDb_multiUserLockError_message(), ex);
247  } catch (CoordinationService.CoordinationServiceException ex) {
248  // This likely just means the coordination service isn't running, which is ok
249  return null;
250  }
251  }
252 
253  @Override
254  boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException {
255  final String objectIdColumnExistsTemplate = "SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='%s' AND column_name='%s')"; //NON-NLS
256  ResultSet resultSet = null;
257  Statement statement = null;
258  boolean columnExists = false;
259  try {
260  statement = conn.createStatement();
261  resultSet = statement.executeQuery(String.format(objectIdColumnExistsTemplate, tableName, columnName));
262  if (resultSet.next()) {
263  columnExists = resultSet.getBoolean(1);
264  }
265  } finally {
266  CentralRepoDbUtil.closeResultSet(resultSet);
267  CentralRepoDbUtil.closeStatement(statement);
268  }
269  return columnExists;
270  }
271 
272 
273 }
synchronized static Logger getLogger(String name)
Definition: Logger.java:124

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