/java/com/google/gerrit/pgm/util/SiteProgram.java
Java | 266 lines | 223 code | 26 blank | 17 comment | 29 complexity | 5ef765b29e55eee95888a2ae2fe4da24 MD5 | raw file
- // Copyright (C) 2009 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.google.gerrit.pgm.util;
- import static com.google.gerrit.server.config.GerritServerConfigModule.getSecureStoreClassName;
- import static com.google.inject.Scopes.SINGLETON;
- import static com.google.inject.Stage.PRODUCTION;
- import com.google.gerrit.common.Die;
- import com.google.gerrit.extensions.events.LifecycleListener;
- import com.google.gerrit.lifecycle.LifecycleModule;
- import com.google.gerrit.metrics.DisabledMetricMaker;
- import com.google.gerrit.metrics.MetricMaker;
- import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
- import com.google.gerrit.server.config.GerritServerConfig;
- import com.google.gerrit.server.config.GerritServerConfigModule;
- import com.google.gerrit.server.config.SitePath;
- import com.google.gerrit.server.git.GitRepositoryManagerModule;
- import com.google.gerrit.server.notedb.NotesMigration;
- import com.google.gerrit.server.schema.DataSourceModule;
- import com.google.gerrit.server.schema.DataSourceProvider;
- import com.google.gerrit.server.schema.DataSourceType;
- import com.google.gerrit.server.schema.DatabaseModule;
- import com.google.gerrit.server.schema.SchemaModule;
- import com.google.gerrit.server.securestore.SecureStoreClassName;
- import com.google.gwtorm.server.OrmException;
- import com.google.inject.AbstractModule;
- import com.google.inject.Binding;
- import com.google.inject.CreationException;
- import com.google.inject.Guice;
- import com.google.inject.Injector;
- import com.google.inject.Key;
- import com.google.inject.Module;
- import com.google.inject.Provider;
- import com.google.inject.ProvisionException;
- import com.google.inject.TypeLiteral;
- import com.google.inject.name.Named;
- import com.google.inject.name.Names;
- import com.google.inject.spi.Message;
- import com.google.inject.util.Providers;
- import java.lang.annotation.Annotation;
- import java.nio.file.Files;
- import java.nio.file.Path;
- import java.nio.file.Paths;
- import java.sql.Connection;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- import javax.sql.DataSource;
- import org.eclipse.jgit.lib.Config;
- import org.kohsuke.args4j.Option;
- public abstract class SiteProgram extends AbstractProgram {
- @Option(
- name = "--site-path",
- aliases = {"-d"},
- usage = "Local directory containing site data"
- )
- private void setSitePath(String path) {
- sitePath = Paths.get(path);
- }
- protected Provider<DataSource> dsProvider;
- private Path sitePath = Paths.get(".");
- protected SiteProgram() {}
- protected SiteProgram(Path sitePath) {
- this.sitePath = sitePath;
- }
- protected SiteProgram(Path sitePath, Provider<DataSource> dsProvider) {
- this.sitePath = sitePath;
- this.dsProvider = dsProvider;
- }
- /** @return the site path specified on the command line. */
- protected Path getSitePath() {
- return sitePath;
- }
- /** Ensures we are running inside of a valid site, otherwise throws a Die. */
- protected void mustHaveValidSite() throws Die {
- if (!Files.exists(sitePath.resolve("etc").resolve("gerrit.config"))) {
- throw die("not a Gerrit site: '" + getSitePath() + "'\nPerhaps you need to run init first?");
- }
- }
- /** @return provides database connectivity and site path. */
- protected Injector createDbInjector(DataSourceProvider.Context context) {
- return createDbInjector(false, context);
- }
- /** @return provides database connectivity and site path. */
- protected Injector createDbInjector(boolean enableMetrics, DataSourceProvider.Context context) {
- Path sitePath = getSitePath();
- List<Module> modules = new ArrayList<>();
- Module sitePathModule =
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
- bind(String.class)
- .annotatedWith(SecureStoreClassName.class)
- .toProvider(Providers.of(getConfiguredSecureStoreClass()));
- }
- };
- modules.add(sitePathModule);
- if (enableMetrics) {
- modules.add(new DropWizardMetricMaker.ApiModule());
- } else {
- modules.add(
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(MetricMaker.class).to(DisabledMetricMaker.class);
- }
- });
- }
- modules.add(
- new LifecycleModule() {
- @Override
- protected void configure() {
- bind(DataSourceProvider.Context.class).toInstance(context);
- if (dsProvider != null) {
- bind(Key.get(DataSource.class, Names.named("ReviewDb")))
- .toProvider(dsProvider)
- .in(SINGLETON);
- if (LifecycleListener.class.isAssignableFrom(dsProvider.getClass())) {
- listener().toInstance((LifecycleListener) dsProvider);
- }
- } else {
- bind(Key.get(DataSource.class, Names.named("ReviewDb")))
- .toProvider(SiteLibraryBasedDataSourceProvider.class)
- .in(SINGLETON);
- listener().to(SiteLibraryBasedDataSourceProvider.class);
- }
- }
- });
- Module configModule = new GerritServerConfigModule();
- modules.add(configModule);
- Injector cfgInjector = Guice.createInjector(sitePathModule, configModule);
- Config cfg = cfgInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
- String dbType;
- if (dsProvider != null) {
- dbType = getDbType(dsProvider);
- } else {
- dbType = cfg.getString("database", null, "type");
- }
- if (dbType == null) {
- throw new ProvisionException("database.type must be defined");
- }
- DataSourceType dst =
- Guice.createInjector(new DataSourceModule(), configModule, sitePathModule)
- .getInstance(Key.get(DataSourceType.class, Names.named(dbType.toLowerCase())));
- modules.add(
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(DataSourceType.class).toInstance(dst);
- }
- });
- modules.add(new DatabaseModule());
- modules.add(new SchemaModule());
- modules.add(cfgInjector.getInstance(GitRepositoryManagerModule.class));
- modules.add(new NotesMigration.Module());
- try {
- return Guice.createInjector(PRODUCTION, modules);
- } catch (CreationException ce) {
- Message first = ce.getErrorMessages().iterator().next();
- Throwable why = first.getCause();
- if (why instanceof SQLException) {
- throw die("Cannot connect to SQL database", why);
- }
- if (why instanceof OrmException
- && why.getCause() != null
- && "Unable to determine driver URL".equals(why.getMessage())) {
- why = why.getCause();
- if (isCannotCreatePoolException(why)) {
- throw die("Cannot connect to SQL database", why.getCause());
- }
- throw die("Cannot connect to SQL database", why);
- }
- StringBuilder buf = new StringBuilder();
- if (why != null) {
- buf.append(why.getMessage());
- why = why.getCause();
- } else {
- buf.append(first.getMessage());
- }
- while (why != null) {
- buf.append("\n caused by ");
- buf.append(why.toString());
- why = why.getCause();
- }
- throw die(buf.toString(), new RuntimeException("DbInjector failed", ce));
- }
- }
- protected final String getConfiguredSecureStoreClass() {
- return getSecureStoreClassName(sitePath);
- }
- private String getDbType(Provider<DataSource> dsProvider) {
- String dbProductName;
- try (Connection conn = dsProvider.get().getConnection()) {
- dbProductName = conn.getMetaData().getDatabaseProductName().toLowerCase();
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- List<Module> modules = new ArrayList<>();
- modules.add(
- new AbstractModule() {
- @Override
- protected void configure() {
- bind(Path.class).annotatedWith(SitePath.class).toInstance(getSitePath());
- }
- });
- modules.add(new GerritServerConfigModule());
- modules.add(new DataSourceModule());
- Injector i = Guice.createInjector(modules);
- List<Binding<DataSourceType>> dsTypeBindings =
- i.findBindingsByType(new TypeLiteral<DataSourceType>() {});
- for (Binding<DataSourceType> binding : dsTypeBindings) {
- Annotation annotation = binding.getKey().getAnnotation();
- if (annotation instanceof Named) {
- if (((Named) annotation).value().toLowerCase().contains(dbProductName)) {
- return ((Named) annotation).value();
- }
- }
- }
- throw new IllegalStateException(
- String.format(
- "Cannot guess database type from the database product name '%s'", dbProductName));
- }
- @SuppressWarnings("deprecation")
- private static boolean isCannotCreatePoolException(Throwable why) {
- return why instanceof org.apache.commons.dbcp.SQLNestedException
- && why.getCause() != null
- && why.getMessage().startsWith("Cannot create PoolableConnectionFactory");
- }
- }