| // Copyright (C) 2017 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.ericsson.gerrit.plugins.gcconductor.postgresqueue; |
| |
| import static com.ericsson.gerrit.plugins.gcconductor.postgresqueue.DatabaseConstants.DRIVER; |
| import static com.ericsson.gerrit.plugins.gcconductor.postgresqueue.DatabaseConstants.createDatabase; |
| import static com.ericsson.gerrit.plugins.gcconductor.postgresqueue.DatabaseConstants.databaseExists; |
| import static com.ericsson.gerrit.plugins.gcconductor.postgresqueue.DatabaseConstants.executeStatement; |
| |
| import com.ericsson.gerrit.plugins.gcconductor.CommonConfig; |
| import com.ericsson.gerrit.plugins.gcconductor.GcQueue; |
| import com.ericsson.gerrit.plugins.gcconductor.ShutdownListener; |
| import com.google.common.annotations.VisibleForTesting; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Inject; |
| import com.google.inject.Provides; |
| import com.google.inject.Singleton; |
| import com.google.inject.internal.UniqueAnnotations; |
| import java.sql.Connection; |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import org.apache.commons.dbcp.BasicDataSource; |
| |
| /** Configures bindings of the Postgres queue implementation. */ |
| public class PostgresModule extends AbstractModule { |
| |
| private static final long EVICT_IDLE_TIME_MS = 1000L * 60; |
| private Class<? extends CommonConfig> commonConfig; |
| |
| public PostgresModule(Class<? extends CommonConfig> commonConfig) { |
| this.commonConfig = commonConfig; |
| } |
| |
| @Override |
| protected void configure() { |
| bind(CommonConfig.class).to(commonConfig); |
| bind(GcQueue.class).to(PostgresQueue.class); |
| bind(ShutdownListener.class) |
| .annotatedWith(UniqueAnnotations.create()) |
| .to(DatabaseAccessCleanUp.class); |
| } |
| |
| /** |
| * Provide access to the gc database. Database will be created if it does not exist. |
| * |
| * @param cfg The database configuration |
| * @return BasicDataSource to access gc database. |
| * @throws SQLException If an error occur while creating the database. |
| */ |
| @Provides |
| @Singleton |
| BasicDataSource provideGcDatabaseAccess(CommonConfig cfg) throws SQLException { |
| BasicDataSource adminDataSource = createDataSource(cfg); |
| try (Connection conn = adminDataSource.getConnection(); |
| Statement stat = conn.createStatement(); |
| ResultSet resultSet = stat.executeQuery(databaseExists(cfg.getDatabaseName()))) { |
| if (!resultSet.next()) { |
| executeStatement(adminDataSource, createDatabase(cfg.getDatabaseName())); |
| } |
| } finally { |
| adminDataSource.close(); |
| } |
| return createDataSource(cfg); |
| } |
| |
| private static BasicDataSource createDataSource(CommonConfig cfg) { |
| BasicDataSource ds = new BasicDataSource(); |
| ds.setDriverClassName(DRIVER); |
| ds.setUrl(cfg.getDatabaseUrl() + cfg.getDatabaseName() + cfg.getDatabaseUrlOptions()); |
| ds.setUsername(cfg.getUsername()); |
| ds.setPassword(cfg.getPassword()); |
| ds.setMinEvictableIdleTimeMillis(EVICT_IDLE_TIME_MS); |
| ds.setTimeBetweenEvictionRunsMillis(EVICT_IDLE_TIME_MS / 2); |
| return ds; |
| } |
| |
| /** Close the database access when plugin is unloaded */ |
| @VisibleForTesting |
| static class DatabaseAccessCleanUp implements ShutdownListener { |
| private final BasicDataSource dataSource; |
| |
| @Inject |
| public DatabaseAccessCleanUp(BasicDataSource dataSource) { |
| this.dataSource = dataSource; |
| } |
| |
| @Override |
| public void onShutdown() { |
| try { |
| dataSource.close(); |
| } catch (SQLException e) { |
| throw new RuntimeException("Failed to close database connection: " + e.getMessage(), e); |
| } |
| } |
| } |
| } |