From fb5548efcb05473eb5788d786e08fb25c21f8aa2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 11 Nov 2009 07:39:21 -0800 Subject: [PATCH] Configure database from gerrit.config Instead of relying on the horribly ugly GerritServer.properties we now configure the database out of gerrit.config through database.* configuration settings. Change-Id: I34734ebe880181480cf149d664368c8e7e469bef Signed-off-by: Shawn O. Pearce --- Documentation/config-gerrit.txt | 72 +++++ .../com/google/gerrit/pgm/CreateSchema.java | 27 +- .../java/com/google/gerrit/pgm/Daemon.java | 18 +- .../google/gerrit/pgm/DataSourceProvider.java | 257 ++++++++++++++++++ .../com/google/gerrit/pgm/SiteProgram.java | 74 +++++ .../server/config/AuthConfigModule.java | 27 ++ .../gerrit/server/config/DatabaseModule.java | 9 - .../server/config/GerritGlobalModule.java | 3 + ...ule.java => GerritServerConfigModule.java} | 12 +- .../config/GerritServerConfigProvider.java | 2 +- ... => SitePathFromSystemConfigProvider.java} | 4 +- .../httpd}/ReviewDbDataSourceProvider.java | 2 +- .../gerrit/httpd/WebAppInitializer.java | 44 ++- 13 files changed, 509 insertions(+), 42 deletions(-) create mode 100644 gerrit-pgm/src/main/java/com/google/gerrit/pgm/DataSourceProvider.java create mode 100644 gerrit-pgm/src/main/java/com/google/gerrit/pgm/SiteProgram.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java rename gerrit-server/src/main/java/com/google/gerrit/server/config/{GerritConfigModule.java => GerritServerConfigModule.java} (67%) rename gerrit-server/src/main/java/com/google/gerrit/server/config/{SitePathProvider.java => SitePathFromSystemConfigProvider.java} (88%) rename {gerrit-server/src/main/java/com/google/gerrit/server/config => gerrit-war/src/main/java/com/google/gerrit/httpd}/ReviewDbDataSourceProvider.java (98%) diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index b55059a638..4cf71b29c9 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -453,6 +453,78 @@ unused mapped spaces fast enough. Default on JGit is false. Although potentially slower, it yields much more predictable behavior. +[[database]]Section database +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The database section configures where Gerrit stores its metadata +records about user accounts and change reviews. + +==== + [database] + type = postgres + hostname = localhost + database = reviewdb + username = gerrit2 + password = s3kr3t +==== + +[[database.type]]database.type:: ++ +Type of database server to connect to. If set this value will be +used to automatically create correct database.driver and database.url +values to open the connection. ++ +* `Postgres` or `PostgreSQL` ++ +Connect to a PostgreSQL database server. ++ +* `H2` ++ +Connect to a local (or remote) H2 database. ++ +* `MySQL` ++ +Connect to a MySQL database server. + ++ +If not specified, database.driver and database.url are used as-is, +and if they are also not specified, defaults to H2. + +[[database.hostname]]database.hostname:: ++ +Hostname of the database server. Defaults to 'localhost'. + +[[database.port]]database.port:: ++ +Port number of the database server. Defaults to the default port +of the server named by database.type. + +[[database.database]]database.database:: ++ +For PostgreSQL or MySQL, the name of the database on the server. ++ +For H2, this is the path to the database, and if not absolute is +relative to `$site_path`. + +[[database.username]]database.username:: ++ +Username to connect to the database server as. + +[[database.password]]database.password:: ++ +Password to authenticate to the database server with. + +[[database.driver]]database.driver:: ++ +Name of the JDBC driver class to connect to the database. +Setting this usually isn't necessary, set database.type instead. + +[[database.url]]database.url:: ++ +JDBC style URL for the database. Setting this usually isn't +necessary, set database.type instead. + + [[gerrit]]Section gerrit ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/CreateSchema.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/CreateSchema.java index ea2604963b..245dd0f414 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/CreateSchema.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/CreateSchema.java @@ -14,21 +14,19 @@ package com.google.gerrit.pgm; -import static com.google.inject.Stage.PRODUCTION; - import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.reviewdb.SchemaVersion; import com.google.gerrit.reviewdb.SystemConfig; -import com.google.gerrit.server.config.DatabaseModule; import com.google.gwtorm.client.SchemaFactory; -import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; +import java.util.Collections; + /** * Creates the Gerrit 2 database schema. */ -public class CreateSchema extends AbstractProgram { +public class CreateSchema extends SiteProgram { @Inject private SystemConfig systemConfig; @@ -37,12 +35,11 @@ public class CreateSchema extends AbstractProgram { @Override public int run() throws Exception { - final Injector injector = - Guice.createInjector(PRODUCTION, new DatabaseModule()); + final Injector injector = createDbInjector(); injector.injectMembers(this); final SchemaVersion sv; - final ReviewDb db = schema.open(); + ReviewDb db = schema.open(); try { sv = db.schemaVersion().get(new SchemaVersion.Key()); } finally { @@ -53,6 +50,20 @@ public class CreateSchema extends AbstractProgram { return 1; } + if (!getSitePath().getAbsolutePath().equals(systemConfig.sitePath)) { + // If the site path in the database doesn't match our command + // line argument, update it. + // + db = schema.open(); + try { + systemConfig = db.systemConfig().get(new SystemConfig.Key()); + systemConfig.sitePath = getSitePath().getAbsolutePath(); + db.systemConfig().update(Collections.singleton(systemConfig)); + } finally { + db.close(); + } + } + System.out.println("Gerrit Code Review initialized."); System.out.println("Current settings:"); System.out.println(" schema version = " + sv.versionNbr); diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java index 82b245637f..64c39ea19d 100644 --- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java @@ -14,23 +14,19 @@ package com.google.gerrit.pgm; -import static com.google.inject.Stage.PRODUCTION; - import com.google.gerrit.httpd.HttpCanonicalWebUrlProvider; import com.google.gerrit.httpd.WebModule; import com.google.gerrit.lifecycle.LifecycleManager; import com.google.gerrit.pgm.http.jetty.JettyEnv; import com.google.gerrit.pgm.http.jetty.JettyModule; +import com.google.gerrit.server.config.AuthConfigModule; import com.google.gerrit.server.config.CanonicalWebUrlModule; import com.google.gerrit.server.config.CanonicalWebUrlProvider; -import com.google.gerrit.server.config.DatabaseModule; -import com.google.gerrit.server.config.GerritConfigModule; import com.google.gerrit.server.config.GerritGlobalModule; import com.google.gerrit.server.config.MasterNodeStartup; import com.google.gerrit.sshd.SshModule; import com.google.gerrit.sshd.commands.MasterCommandModule; import com.google.gerrit.sshd.commands.SlaveCommandModule; -import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Provider; @@ -45,7 +41,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; /** Run SSH daemon portions of Gerrit. */ -public class Daemon extends AbstractProgram { +public class Daemon extends SiteProgram { private static final Logger log = LoggerFactory.getLogger(Daemon.class); @Option(name = "--enable-httpd", usage = "Enable the internal HTTP daemon") @@ -92,8 +88,8 @@ public class Daemon extends AbstractProgram { throw die("--enable-httpd currently requires --enable-sshd"); } - dbInjector = Guice.createInjector(PRODUCTION, new DatabaseModule()); - cfgInjector = dbInjector.createChildInjector(new GerritConfigModule()); + dbInjector = createDbInjector(); + cfgInjector = createCfgInjector(); sysInjector = createSysInjector(); manager.add(dbInjector, cfgInjector, sysInjector); @@ -121,6 +117,12 @@ public class Daemon extends AbstractProgram { return com.google.gerrit.common.Version.getVersion(); } + private Injector createCfgInjector() { + final List modules = new ArrayList(); + modules.add(new AuthConfigModule()); + return dbInjector.createChildInjector(modules); + } + private Injector createSysInjector() { final List modules = new ArrayList(); modules.add(cfgInjector.getInstance(GerritGlobalModule.class)); diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/DataSourceProvider.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/DataSourceProvider.java new file mode 100644 index 0000000000..e82c739dbe --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/DataSourceProvider.java @@ -0,0 +1,257 @@ +// 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; + +import com.google.gerrit.lifecycle.LifecycleListener; +import com.google.gerrit.server.config.ConfigUtil; +import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.config.SitePath; +import com.google.gwtorm.jdbc.SimpleDataSource; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.ProvisionException; +import com.google.inject.Singleton; + +import org.apache.commons.dbcp.BasicDataSource; +import org.eclipse.jgit.lib.Config; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.sql.SQLException; +import java.util.Properties; + +import javax.sql.DataSource; + +/** Provides access to the DataSource. */ +@Singleton +public final class DataSourceProvider implements Provider, + LifecycleListener { + private final DataSource ds; + + @Inject + DataSourceProvider(@SitePath final File sitePath, + @GerritServerConfig final Config cfg) { + ds = open(sitePath, cfg); + } + + @Override + public synchronized DataSource get() { + return ds; + } + + @Override + public void start() { + } + + @Override + public synchronized void stop() { + if (ds instanceof BasicDataSource) { + try { + ((BasicDataSource) ds).close(); + } catch (SQLException e) { + // Ignore the close failure. + } + } + } + + public static enum Type { + DEFAULT, JDBC, POSTGRES, POSTGRESQL, H2, MYSQL; + } + + private DataSource open(final File sitePath, final Config cfg) { + Type type = ConfigUtil.getEnum(cfg, "database", null, "type", Type.DEFAULT); + String driver = optional(cfg, "driver"); + String url = optional(cfg, "url"); + String username = optional(cfg, "username"); + String password = optional(cfg, "password"); + String hostname = optional(cfg, "hostname"); + String port = optional(cfg, "port"); + if (hostname == null) { + hostname = "localhost"; + } + + if (Type.DEFAULT == type && (driver == null || driver.isEmpty())) { + if (url != null && url.isEmpty()) { + + if (url.startsWith("jdbc:postgresql:")) { + type = Type.POSTGRES; + } else if (url.startsWith("postgresql:")) { + url = "jdbc:" + url; + type = Type.POSTGRES; + } else if (url.startsWith("postgres:")) { + url = "jdbc:postgresql:" + url.substring(url.indexOf(':') + 1); + type = Type.POSTGRES; + + } else if (url.startsWith("jdbc:h2:")) { + type = Type.H2; + } else if (url.startsWith("h2:")) { + url = "jdbc:" + url; + type = Type.H2; + + } else if (url.startsWith("jdbc:mysql:")) { + type = Type.MYSQL; + } else if (url.startsWith("mysql:")) { + url = "jdbc:" + url; + type = Type.MYSQL; + + } + + } else if (url == null || url.isEmpty()) { + type = Type.H2; + } + } + + switch (type) { + case POSTGRES: + case POSTGRESQL: { + final String pfx = "jdbc:postgresql://"; + driver = "org.postgresql.Driver"; + if (url == null) { + final StringBuilder b = new StringBuilder(); + b.append(pfx); + b.append(hostname); + if (port != null && !port.isEmpty()) { + b.append(":"); + b.append(port); + } + b.append("/"); + b.append(required(cfg, "database")); + url = b.toString(); + } + if (url == null || !url.startsWith(pfx)) { + throw new IllegalArgumentException("database.url must be " + pfx + + " and not " + url); + } + break; + } + + case H2: { + final String pfx = "jdbc:h2:"; + driver = "org.h2.Driver"; + if (url == null) { + String database = optional(cfg, "database"); + if (database == null || database.isEmpty()) { + database = "ReviewDB"; + } + + File db = new File(database); + if (!db.isAbsolute()) { + db = new File(sitePath, database).getAbsoluteFile(); + } + url = pfx + db.toURI().toString(); + } + if (url == null || !url.startsWith(pfx)) { + throw new IllegalArgumentException("database.url must be " + pfx + + " and not " + url); + } + break; + } + + case MYSQL: { + final String pfx = "jdbc:mysql://"; + driver = "com.mysql.jdbc.Driver"; + if (url == null) { + final StringBuilder b = new StringBuilder(); + b.append(pfx); + b.append(hostname); + if (port != null && !port.isEmpty()) { + b.append(":"); + b.append(port); + } + b.append("/"); + b.append(required(cfg, "database")); + url = b.toString(); + } + if (url == null || !url.startsWith(pfx)) { + throw new IllegalArgumentException("database.url must be " + pfx + + " and not " + url); + } + break; + } + + case DEFAULT: + case JDBC: + default: + driver = required(cfg, "driver"); + url = required(cfg, "url"); + if (!url.startsWith("jdbc:")) { + throw new IllegalArgumentException("database.url must be jdbc: style"); + } + break; + } + + boolean usePool; + if (url.startsWith("jdbc:mysql:")) { + // MySQL has given us trouble with the connection pool, + // sometimes the backend disconnects and the pool winds + // up with a stale connection. Fortunately opening up + // a new MySQL connection is usually very fast. + // + usePool = false; + } else { + usePool = true; + } + usePool = cfg.getBoolean("database", "connectionpool", usePool); + + if (usePool) { + final BasicDataSource ds = new BasicDataSource(); + ds.setDriverClassName(driver); + ds.setUrl(url); + if (username != null && !username.isEmpty()) { + ds.setUsername(username); + } + if (password != null && !password.isEmpty()) { + ds.setPassword(password); + } + ds.setMaxActive(cfg.getInt("database", "poollimit", 8)); + ds.setMinIdle(cfg.getInt("database", "poolminidle", 4)); + ds.setMaxIdle(cfg.getInt("database", "poolmaxidle", 4)); + ds.setMaxWait(cfg.getInt("database", "poolmaxwait", 30000)); + ds.setInitialSize(ds.getMinIdle()); + return ds; + + } else { + // Don't use the connection pool. + // + try { + final Properties p = new Properties(); + p.setProperty("driver", driver); + p.setProperty("url", url); + if (username != null) { + p.setProperty("user", username); + } + if (password != null) { + p.setProperty("password", password); + } + return new SimpleDataSource(p); + } catch (SQLException se) { + throw new ProvisionException("Database unavailable", se); + } + } + } + + private static String optional(final Config config, final String name) { + return config.getString("database", null, name); + } + + private static String required(final Config config, final String name) { + final String v = optional(config, name); + if (v == null || "".equals(v)) { + throw new IllegalArgumentException("No database." + name + " configured"); + } + return v; + } +} diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SiteProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SiteProgram.java new file mode 100644 index 0000000000..f0d16e43c7 --- /dev/null +++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/SiteProgram.java @@ -0,0 +1,74 @@ +// 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; + +import static com.google.inject.Scopes.SINGLETON; +import static com.google.inject.Stage.PRODUCTION; + +import com.google.gerrit.lifecycle.LifecycleModule; +import com.google.gerrit.server.config.DatabaseModule; +import com.google.gerrit.server.config.GerritServerConfigModule; +import com.google.gerrit.server.config.SitePath; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.name.Names; + +import org.kohsuke.args4j.Option; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; + +public abstract class SiteProgram extends AbstractProgram { + @Option(name = "--site-path", aliases = {"-d"}, usage = "Local directory containing site data") + private File sitePath = new File("."); + + /** @return the site path specified on the command line. */ + protected File getSitePath() { + File path = sitePath.getAbsoluteFile(); + if (".".equals(path.getName())) { + path = path.getParentFile(); + } + return path; + } + + /** @return provides database connectivity and site path. */ + protected Injector createDbInjector() { + final File sitePath = getSitePath(); + final List modules = new ArrayList(); + modules.add(new AbstractModule() { + @Override + protected void configure() { + bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath); + } + }); + modules.add(new LifecycleModule() { + @Override + protected void configure() { + bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider( + DataSourceProvider.class).in(SINGLETON); + listener().to(DataSourceProvider.class); + } + }); + modules.add(new GerritServerConfigModule()); + modules.add(new DatabaseModule()); + return Guice.createInjector(PRODUCTION, modules); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java new file mode 100644 index 0000000000..e5d4ba8c31 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/AuthConfigModule.java @@ -0,0 +1,27 @@ +// 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.server.config; + +import static com.google.inject.Scopes.SINGLETON; + +import com.google.inject.AbstractModule; + +/** Creates {@link AuthConfig} from {@link GerritServerConfig}. */ +public class AuthConfigModule extends AbstractModule { + @Override + protected void configure() { + bind(AuthConfig.class).in(SINGLETON); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java index 659872a2be..21ab1b8283 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/DatabaseModule.java @@ -20,21 +20,12 @@ import com.google.gerrit.reviewdb.ReviewDb; import com.google.gerrit.reviewdb.SystemConfig; import com.google.gwtorm.client.SchemaFactory; import com.google.gwtorm.jdbc.Database; -import com.google.inject.Key; import com.google.inject.TypeLiteral; -import com.google.inject.name.Names; - -import javax.sql.DataSource; /** Loads the database with standard dependencies. */ public class DatabaseModule extends FactoryModule { - public static final Key DS = - Key.get(DataSource.class, Names.named("ReviewDb")); - @Override protected void configure() { - bind(DS).toProvider(ReviewDbDataSourceProvider.class).in(SINGLETON); - bind(new TypeLiteral>() {}).to( new TypeLiteral>() {}).in(SINGLETON); bind(new TypeLiteral>() {}).toProvider( diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java index 239ff533e8..c32cc468aa 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java @@ -19,6 +19,7 @@ import static com.google.inject.Scopes.SINGLETON; import com.google.gerrit.common.data.ApprovalTypes; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.reviewdb.AuthType; +import com.google.gerrit.reviewdb.Project; import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.FileTypeRegistry; import com.google.gerrit.server.GerritPersonIdent; @@ -87,6 +88,8 @@ public class GerritGlobalModule extends FactoryModule { break; } + bind(Project.NameKey.class).annotatedWith(WildProjectName.class) + .toProvider(WildProjectNameProvider.class).in(SINGLETON); bind(ApprovalTypes.class).toProvider(ApprovalTypesProvider.class).in( SINGLETON); bind(EmailExpander.class).toProvider(EmailExpanderProvider.class).in( diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfigModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java similarity index 67% rename from gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfigModule.java rename to gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java index a512654509..0ad6b9d934 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritConfigModule.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigModule.java @@ -16,23 +16,15 @@ package com.google.gerrit.server.config; import static com.google.inject.Scopes.SINGLETON; -import com.google.gerrit.reviewdb.Project; import com.google.inject.AbstractModule; import org.eclipse.jgit.lib.Config; -import java.io.File; - -/** Injection for the really primitive configuration data. */ -public class GerritConfigModule extends AbstractModule { +/** Creates {@link GerritServerConfig}. */ +public class GerritServerConfigModule extends AbstractModule { @Override protected void configure() { - bind(File.class).annotatedWith(SitePath.class).toProvider( - SitePathProvider.class).in(SINGLETON); - bind(Project.NameKey.class).annotatedWith(WildProjectName.class) - .toProvider(WildProjectNameProvider.class).in(SINGLETON); bind(Config.class).annotatedWith(GerritServerConfig.class).toProvider( GerritServerConfigProvider.class).in(SINGLETON); - bind(AuthConfig.class).in(SINGLETON); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java index 8854a602b4..dd1ff1eac0 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java @@ -28,7 +28,7 @@ import java.io.File; import java.io.IOException; /** Provides {@link Config} annotated with {@link GerritServerConfig}. */ -public class GerritServerConfigProvider implements Provider { +class GerritServerConfigProvider implements Provider { private static final Logger log = LoggerFactory.getLogger(GerritServerConfigProvider.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java similarity index 88% rename from gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathProvider.java rename to gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java index f9fb021c84..5b5dcc1f62 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathProvider.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SitePathFromSystemConfigProvider.java @@ -21,11 +21,11 @@ import com.google.inject.Provider; import java.io.File; /** Provides {@link java.io.File} annotated with {@link SitePath}. */ -public class SitePathProvider implements Provider { +public class SitePathFromSystemConfigProvider implements Provider { private final File path; @Inject - SitePathProvider(final SystemConfig config) { + SitePathFromSystemConfigProvider(final SystemConfig config) { final String p = config.sitePath; path = new File(p != null && p.length() > 0 ? p : ".").getAbsoluteFile(); } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ReviewDbDataSourceProvider.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/ReviewDbDataSourceProvider.java similarity index 98% rename from gerrit-server/src/main/java/com/google/gerrit/server/config/ReviewDbDataSourceProvider.java rename to gerrit-war/src/main/java/com/google/gerrit/httpd/ReviewDbDataSourceProvider.java index a8c5d3e6c5..8a0d50b35f 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ReviewDbDataSourceProvider.java +++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/ReviewDbDataSourceProvider.java @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.google.gerrit.server.config; +package com.google.gerrit.httpd; import com.google.gerrit.lifecycle.LifecycleListener; import com.google.gwtorm.jdbc.SimpleDataSource; diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java index 9e9aab89d6..7a4dac0821 100644 --- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java +++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java @@ -14,33 +14,43 @@ package com.google.gerrit.httpd; +import static com.google.inject.Scopes.SINGLETON; import static com.google.inject.Stage.PRODUCTION; import com.google.gerrit.lifecycle.LifecycleManager; +import com.google.gerrit.lifecycle.LifecycleModule; +import com.google.gerrit.server.config.AuthConfigModule; import com.google.gerrit.server.config.CanonicalWebUrlModule; import com.google.gerrit.server.config.DatabaseModule; -import com.google.gerrit.server.config.GerritConfigModule; import com.google.gerrit.server.config.GerritGlobalModule; +import com.google.gerrit.server.config.GerritServerConfigModule; import com.google.gerrit.server.config.MasterNodeStartup; +import com.google.gerrit.server.config.SitePath; +import com.google.gerrit.server.config.SitePathFromSystemConfigProvider; import com.google.gerrit.sshd.SshModule; import com.google.gerrit.sshd.commands.MasterCommandModule; +import com.google.inject.AbstractModule; 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.name.Names; import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.spi.Message; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.servlet.ServletContextEvent; import javax.servlet.http.HttpServletRequest; +import javax.sql.DataSource; /** Configures the web application environment for Gerrit Code Review. */ public class WebAppInitializer extends GuiceServletContextListener { @@ -57,7 +67,7 @@ public class WebAppInitializer extends GuiceServletContextListener { private synchronized void init() { if (manager == null) { try { - dbInjector = Guice.createInjector(PRODUCTION, new DatabaseModule()); + dbInjector = createDbInjector(); } catch (CreationException ce) { final Message first = ce.getErrorMessages().iterator().next(); final StringBuilder buf = new StringBuilder(); @@ -77,7 +87,7 @@ public class WebAppInitializer extends GuiceServletContextListener { throw new CreationException(Collections.singleton(first)); } - cfgInjector = dbInjector.createChildInjector(new GerritConfigModule()); + cfgInjector = createCfgInjector(); sysInjector = createSysInjector(); sshInjector = createSshInjector(); webInjector = createWebInjector(); @@ -103,6 +113,34 @@ public class WebAppInitializer extends GuiceServletContextListener { } } + private Injector createDbInjector() { + final List modules = new ArrayList(); + modules.add(new LifecycleModule() { + @Override + protected void configure() { + bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider( + ReviewDbDataSourceProvider.class).in(SINGLETON); + listener().to(ReviewDbDataSourceProvider.class); + } + }); + modules.add(new DatabaseModule()); + return Guice.createInjector(PRODUCTION, modules); + } + + private Injector createCfgInjector() { + final List modules = new ArrayList(); + modules.add(new AbstractModule() { + @Override + protected void configure() { + bind(File.class).annotatedWith(SitePath.class).toProvider( + SitePathFromSystemConfigProvider.class).in(SINGLETON); + } + }); + modules.add(new GerritServerConfigModule()); + modules.add(new AuthConfigModule()); + return dbInjector.createChildInjector(modules); + } + private Injector createSysInjector() { final List modules = new ArrayList(); modules.add(cfgInjector.getInstance(GerritGlobalModule.class));