Abstract out concepts of DataSourceType and DatabaseConfigInitializer.

Encapsulate data source specific logic into subclasses of DataSourceType
and DatabaseConfigInitializer.  DataSourceType and
DatabaseConfigInitializer are separated because we need them at
different stages (init vs runtime) and they also need to exist in
different projects with different dependencies.

This is a first step toward providing support for different database
platforms as plugins.

Change-Id: I01ea666ef7f682d6137f0e64005d979dd706f67b
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
Signed-off-by: Sasa Zivkov <sasa.zivkov@sap.com>
This commit is contained in:
Sasa Zivkov
2012-06-27 16:44:49 +02:00
committed by Edwin Kempin
parent 05acbe4c0a
commit b53bffe1b9
27 changed files with 798 additions and 222 deletions

View File

@@ -0,0 +1,25 @@
// Copyright (C) 2012 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.init;
/** Abstraction of initializer for the database section */
interface DatabaseConfigInitializer {
/**
* Performs database platform specific configuration steps and writes
* configuration parameters into the given database section
*/
public void initConfig(Section databaseSection);
}

View File

@@ -0,0 +1,41 @@
// Copyright (C) 2012 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.init;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
public class DatabaseConfigModule extends AbstractModule {
private final SitePaths site;
public DatabaseConfigModule(final SitePaths site) {
this.site = site;
}
@Override
protected void configure() {
bind(SitePaths.class).toInstance(site);
bind(DatabaseConfigInitializer.class).annotatedWith(
Names.named("h2")).to(H2Initializer.class);
bind(DatabaseConfigInitializer.class).annotatedWith(
Names.named("jdbc")).to(JDBCInitializer.class);
bind(DatabaseConfigInitializer.class).annotatedWith(
Names.named("mysql")).to(MySqlInitializer.class);
bind(DatabaseConfigInitializer.class).annotatedWith(
Names.named("postgresql")).to(PostgreSQLInitializer.class);
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2012 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.init;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import java.io.File;
class H2Initializer implements DatabaseConfigInitializer {
private final SitePaths site;
@Inject
H2Initializer(final SitePaths site) {
this.site = site;
}
@Override
public void initConfig(Section databaseSection) {
String path = databaseSection.get("database");
if (path == null) {
path = "db/ReviewDB";
databaseSection.set("database", path);
}
File db = site.resolve(path);
if (db == null) {
throw InitUtil.die("database.database must be supplied for H2");
}
db = db.getParentFile();
if (!db.exists() && !db.mkdirs()) {
throw InitUtil.die("cannot create database.database "
+ db.getAbsolutePath());
}
}
}

View File

@@ -14,17 +14,24 @@
package com.google.gerrit.pgm.init;
import static com.google.gerrit.pgm.init.InitUtil.die;
import static com.google.gerrit.pgm.init.InitUtil.username;
import static com.google.gerrit.server.schema.DataSourceProvider.Type.H2;
import static com.google.inject.Stage.PRODUCTION;
import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import java.io.File;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/** Initialize the {@code database} configuration section. */
@Singleton
@@ -46,59 +53,28 @@ class InitDatabase implements InitStep {
public void run() {
ui.header("SQL Database");
final DataSourceProvider.Type db_type =
database.select("Database server type", "type", H2);
Set<String> allowedValues = new TreeSet<String>();
Injector i = Guice.createInjector(PRODUCTION, new DatabaseConfigModule(site));
List<Binding<DatabaseConfigInitializer>> dbConfigBindings =
i.findBindingsByType(new TypeLiteral<DatabaseConfigInitializer>() {});
for (Binding<DatabaseConfigInitializer> binding : dbConfigBindings) {
Annotation annotation = binding.getKey().getAnnotation();
if (annotation instanceof Named) {
allowedValues.add(((Named) annotation).value());
}
}
switch (db_type) {
case MYSQL:
String dbType =
database.select("Database server type", "type", "h2", allowedValues);
DatabaseConfigInitializer dci =
i.getInstance(Key.get(DatabaseConfigInitializer.class,
Names.named(dbType.toLowerCase())));
if (dci instanceof MySqlInitializer) {
libraries.mysqlDriver.downloadRequired();
break;
}
final boolean userPassAuth;
switch (db_type) {
case H2: {
userPassAuth = false;
String path = database.get("database");
if (path == null) {
path = "db/ReviewDB";
database.set("database", path);
}
File db = site.resolve(path);
if (db == null) {
throw die("database.database must be supplied for H2");
}
db = db.getParentFile();
if (!db.exists() && !db.mkdirs()) {
throw die("cannot create database.database " + db.getAbsolutePath());
}
break;
}
case JDBC: {
userPassAuth = true;
database.string("Driver class name", "driver", null);
database.string("URL", "url", null);
break;
}
case POSTGRESQL:
case MYSQL: {
userPassAuth = true;
final String defPort = "(" + db_type.toString() + " default)";
database.string("Server hostname", "hostname", "localhost");
database.string("Server port", "port", defPort, true);
database.string("Database name", "database", "reviewdb");
break;
}
default:
throw die("internal bug, database " + db_type + " not supported");
}
if (userPassAuth) {
database.string("Database username", "username", username());
database.password("username", "password");
}
dci.initConfig(database);
}
}

View File

@@ -0,0 +1,28 @@
// Copyright (C) 2012 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.init;
import static com.google.gerrit.pgm.init.InitUtil.username;
class JDBCInitializer implements DatabaseConfigInitializer {
@Override
public void initConfig(Section databaseSection) {
databaseSection.string("Driver class name", "driver", null);
databaseSection.string("URL", "url", null);
databaseSection.string("Database username", "username", username());
databaseSection.password("username", "password");
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2012 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.init;
import static com.google.gerrit.pgm.init.InitUtil.username;
class MySqlInitializer implements DatabaseConfigInitializer {
@Override
public void initConfig(Section databaseSection) {
final String defPort = "(mysql default)";
databaseSection.string("Server hostname", "hostname", "localhost");
databaseSection.string("Server port", "port", defPort, true);
databaseSection.string("Database name", "database", "reviewdb");
databaseSection.string("Database username", "username", username());
databaseSection.password("username", "password");
}
}

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2012 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.init;
import static com.google.gerrit.pgm.init.InitUtil.username;
class PostgreSQLInitializer implements DatabaseConfigInitializer {
@Override
public void initConfig(Section databaseSection) {
final String defPort = "(postgresql default)";
databaseSection.string("Server hostname", "hostname", "localhost");
databaseSection.string("Server port", "port", defPort, true);
databaseSection.string("Database name", "database", "reviewdb");
databaseSection.string("Database username", "username", username());
databaseSection.password("username", "password");
}
}

View File

@@ -23,6 +23,7 @@ import com.google.inject.assistedinject.Assisted;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
/** Helper to edit a section of the configuration files. */
class Section {
@@ -125,6 +126,16 @@ class Section {
return newValue;
}
String select(final String title, final String name, final String dv,
Set<String> allowedValues) {
final String ov = get(name);
String nv = ui.readString(ov != null ? ov : dv, allowedValues, "%s", title);
if (!eq(ov, nv)) {
set(name, nv);
}
return nv;
}
String password(final String username, final String password) {
final String ov = getSecure(password);
@@ -166,6 +177,10 @@ class Section {
}
}
String getName() {
return section;
}
private static boolean eq(final String a, final String b) {
if (a == null && b == null) {
return true;

View File

@@ -20,7 +20,6 @@ import static com.google.gerrit.pgm.init.InitUtil.saveSecure;
import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.util.SocketUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -122,7 +121,7 @@ class UpgradeFrom2_0_x implements InitStep {
String url = oldprop.getProperty("url");
if (url != null && !convertUrl(database, url)) {
database.set("type", DataSourceProvider.Type.JDBC);
database.set("type", "jdbc");
database.set("driver", oldprop.getProperty("driver"));
database.set("url", url);
}
@@ -189,7 +188,7 @@ class UpgradeFrom2_0_x implements InitStep {
if (url.startsWith("jdbc:h2:file:")) {
url = url.substring("jdbc:h2:file:".length());
database.set("type", DataSourceProvider.Type.H2);
database.set("type", "h2");
database.set("database", url);
return true;
}
@@ -202,7 +201,7 @@ class UpgradeFrom2_0_x implements InitStep {
}
final InetSocketAddress addr = SocketUtil.parse(url.substring(0, sl), 0);
database.set("type", DataSourceProvider.Type.POSTGRESQL);
database.set("type", "postgresql");
sethost(database, addr);
database.set("database", url.substring(sl + 1));
setuser(database, username, password);
@@ -211,7 +210,7 @@ class UpgradeFrom2_0_x implements InitStep {
if (url.startsWith("jdbc:postgresql:")) {
url = url.substring("jdbc:postgresql:".length());
database.set("type", DataSourceProvider.Type.POSTGRESQL);
database.set("type", "postgresql");
database.set("hostname", "localhost");
database.set("database", url);
setuser(database, username, password);
@@ -226,7 +225,7 @@ class UpgradeFrom2_0_x implements InitStep {
}
final InetSocketAddress addr = SocketUtil.parse(url.substring(0, sl), 0);
database.set("type", DataSourceProvider.Type.MYSQL);
database.set("type", "mysql");
sethost(database, addr);
database.set("database", url.substring(sl + 1));
setuser(database, username, password);