Implement schema initialization and upgrade
diff --git a/BUCK b/BUCK
index a557b76..2ba6ac4 100644
--- a/BUCK
+++ b/BUCK
@@ -8,6 +8,7 @@
     'Gerrit-PluginName: ci',
     'Gerrit-Module: com.googlesource.gerrit.plugins.ci.GlobalModule',
     'Gerrit-SshModule: com.googlesource.gerrit.plugins.ci.SshModule',
+    'Gerrit-InitStep: com.googlesource.gerrit.plugins.ci.init.InitPlugin',
     'Implementation-Title: CI plugin',
     'Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/ci',
   ],
diff --git a/README.md b/README.md
index 1e33399..8f662db 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,54 @@
 Gerrit CI reporting and visualization plugin
 ============================================
 
-This plugin allow CI system to report result outcome to Gerrit. The result are visualized on change screen. Reporting can be done through SSH commands or REST API.
-
-Database schema doesn't created automatically for now. The scripts are povided separately:
-Prebuilt artifacts 
+This plugin allows CI system to report result outcome to Gerrit. The result is visualized on change screen pet patch set. Reporting can be done through SSH command or REST API.
 
 Persistense
 -----------
 
-CI data is stored in seperate database (not review DB used by Gerrit
+CI data is stored in seperate CI database (not review DB used by Gerrit
 itself). The following database dialects are currently supported:
 
+* Derby
 * H2
 * MySQL
 * Oracle
 * PostgreSQL
 
-Database schema doesn't created automatically for now. The script is povided for H2 only for now.
+Schema initialization
+---------------------
+
+Database is initialized and the schema is created with init plugin step:
 
 ```
-CREATE TABLE PATCH_SET_VERIFICATIONS(
-VALUE SMALLINT DEFAULT 0 NOT NULL,
-GRANTED TIMESTAMP NOT NULL,
-URL VARCHAR(255),
-VERIFIER VARCHAR(255),
-COMMENT VARCHAR(255),
-CHANGE_ID INTEGER DEFAULT 0 NOT NULL,
-PATCH_SET_ID INTEGER DEFAULT 0 NOT NULL,
-CATEGORY_ID VARCHAR(255) DEFAULT '' NOT NULL,
-PRIMARY KEY(CHANGE_ID, PATCH_SET_ID, CATEGORY_ID));
+*** SQL Database for CI plugin
+*** 
+
+Database server type           [h2]: ?
+       Supported options are:
+         derby
+         h2
+         mysql
+         oracle
+         postgresql
+Database server type           [h2]: h2
+
+Initialized <gerrit-site>
+```
+
+Schema upgrade
+--------------
+
+Schema upgrade takes place in init plugin step:
+
+```
+*** SQL Database for CI plugin
+*** 
+
+Database server type           [h2]: 
+
+Upgrading schema to 2 ...
+Migrating data to schema 2 ...
 ```
 
 Example for SSH command
@@ -66,9 +85,14 @@
 ----
 
 * Documentation
-* Schema initialization and upgrade
 * UI integration
 
+Pending changes in Gerrit core
+------------------------------
+
+https://gerrit-review.googlesource.com/72797
+
+
 License
 -------
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java
index 4dcb816..8513818 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/GlobalModule.java
@@ -16,8 +16,8 @@
 
 import static com.google.inject.Scopes.SINGLETON;
 
+import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.lifecycle.LifecycleModule;
-import com.google.inject.AbstractModule;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Key;
@@ -35,9 +35,9 @@
 
 import javax.sql.DataSource;
 
-public class GlobalModule extends AbstractModule {
+public class GlobalModule extends FactoryModule {
 
-  private final  Injector injector;
+  private final Injector injector;
 
   @Inject
   GlobalModule(Injector injector) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/InitPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/ci/InitPlugin.java
deleted file mode 100644
index 8ce45a3..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/InitPlugin.java
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci;
-
-import com.google.gerrit.pgm.init.api.InitStep;
-import com.google.inject.Inject;
-
-import com.googlesource.gerrit.plugins.ci.server.CiDb;
-
-public class InitPlugin implements InitStep {
-
-  // TODO(davido): Add site initialization logic
-  @SuppressWarnings("unused")
-  private final CiDb ciDb;
-
-  @Inject
-  InitPlugin(CiDb ciDb) {
-    this.ciDb = ciDb;
-  }
-
-  @Override
-  public void run() throws Exception {
-  }
-
-  @Override
-  public void postRun() throws Exception {
-  }
-}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/DatabaseConfigInitializer.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/DatabaseConfigInitializer.java
new file mode 100644
index 0000000..6cbb05f
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/DatabaseConfigInitializer.java
@@ -0,0 +1,27 @@
+// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci.init;
+
+import com.google.gerrit.pgm.init.api.Section;
+
+/** Abstraction of initializer for the database section */
+interface DatabaseConfigInitializer {
+
+  /**
+   * Performs database platform specific configuration steps and writes
+   * configuration parameters into the given database section
+   */
+  void initConfig(Section pluginSection);
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/DatabaseConfigModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/DatabaseConfigModule.java
new file mode 100644
index 0000000..1fdd68c
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/DatabaseConfigModule.java
@@ -0,0 +1,43 @@
+// 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.googlesource.gerrit.plugins.ci.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("derby")).to(DerbyInitializer.class);
+    bind(DatabaseConfigInitializer.class).annotatedWith(
+        Names.named("h2")).to(H2Initializer.class);
+    bind(DatabaseConfigInitializer.class).annotatedWith(
+        Names.named("mysql")).to(MySqlInitializer.class);
+    bind(DatabaseConfigInitializer.class).annotatedWith(
+        Names.named("oracle")).to(OracleInitializer.class);
+    bind(DatabaseConfigInitializer.class).annotatedWith(
+        Names.named("postgresql")).to(PostgreSQLInitializer.class);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/DerbyInitializer.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/DerbyInitializer.java
new file mode 100644
index 0000000..06c287b
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/DerbyInitializer.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci.init;
+
+import static com.google.gerrit.pgm.init.api.InitUtil.die;
+
+import com.google.gerrit.common.FileUtil;
+import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+
+import java.nio.file.Path;
+
+class DerbyInitializer implements DatabaseConfigInitializer {
+
+  private final SitePaths site;
+
+  @Inject
+  DerbyInitializer(SitePaths site) {
+    this.site = site;
+  }
+
+  @Override
+  public void initConfig(Section configSection) {
+    String path = configSection.get("database");
+    Path db;
+    if (path == null) {
+      db = site.resolve("db").resolve("CiDB");
+      configSection.set("database", db.toString());
+    } else {
+      db = site.resolve(path);
+    }
+    if (db == null) {
+      throw die("database.database must be supplied for Derby");
+    }
+    db = db.getParent();
+    FileUtil.mkdirsOrDie(db, "cannot create database.database");
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/H2Initializer.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/H2Initializer.java
new file mode 100644
index 0000000..7b466c1
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/H2Initializer.java
@@ -0,0 +1,51 @@
+// 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.googlesource.gerrit.plugins.ci.init;
+
+import static com.google.gerrit.pgm.init.api.InitUtil.die;
+
+import com.google.gerrit.common.FileUtil;
+import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
+
+import java.nio.file.Path;
+
+class H2Initializer implements DatabaseConfigInitializer {
+
+  private final SitePaths site;
+
+  @Inject
+  H2Initializer(SitePaths site) {
+    this.site = site;
+  }
+
+  @Override
+  public void initConfig(Section configSection) {
+    String path = configSection.get("database");
+    Path db;
+    if (path == null) {
+      db = site.resolve("db").resolve("CiDB");
+      configSection.set("database", db.toString());
+    } else {
+      db = site.resolve(path);
+    }
+    if (db == null) {
+      throw die("database.database must be supplied for H2");
+    }
+    db = db.getParent();
+    FileUtil.mkdirsOrDie(db, "cannot create database.database");
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/InitPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/InitPlugin.java
new file mode 100644
index 0000000..e81cc5a
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/InitPlugin.java
@@ -0,0 +1,269 @@
+// Copyright (C) 2015 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.googlesource.gerrit.plugins.ci.init;
+
+import static com.google.inject.Scopes.SINGLETON;
+import static com.google.inject.Stage.PRODUCTION;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.init.api.InitStep;
+import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.reviewdb.client.CurrentSchemaVersion;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.gwtorm.jdbc.JdbcExecutor;
+import com.google.gwtorm.jdbc.JdbcSchema;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.gwtorm.server.StatementExecutor;
+import com.google.inject.AbstractModule;
+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.Module;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
+import com.google.inject.name.Named;
+import com.google.inject.name.Names;
+
+import com.googlesource.gerrit.plugins.ci.server.CiDb;
+import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceModule;
+import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceProvider;
+import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceType;
+import com.googlesource.gerrit.plugins.ci.server.schema.CiDataSourceTypeGuesser;
+import com.googlesource.gerrit.plugins.ci.server.schema.CiDatabaseModule;
+import com.googlesource.gerrit.plugins.ci.server.schema.SchemaVersion;
+import com.googlesource.gerrit.plugins.ci.server.schema.UpdateUI;
+
+import java.lang.annotation.Annotation;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.sql.DataSource;
+
+@Singleton
+public class InitPlugin implements InitStep {
+  private final ConsoleUI ui;
+  private final SitePaths site;
+  private final Section configSection;
+  private final Injector parent;
+  private SchemaFactory<CiDb> dbFactory;
+  private Provider<SchemaVersion> updater;
+
+  @Inject
+  InitPlugin(Section.Factory sections,
+      @PluginName String pluginName,
+      ConsoleUI ui,
+      SitePaths site,
+      Injector parent) {
+    this.ui = ui;
+    this.site = site;
+    this.configSection = sections.get("plugin", pluginName);
+    this.parent = parent;
+  }
+
+  @Override
+  public void run() throws Exception {
+    ui.header("SQL Database for CI plugin");
+
+    Set<String> allowedValues = Sets.newTreeSet();
+    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());
+      }
+    }
+
+    if (!Strings.isNullOrEmpty(configSection.get("dbUrl"))
+        && Strings.isNullOrEmpty(configSection.get("dbType"))) {
+      configSection.set("dbType", "h2");
+    }
+
+    String dbType =
+        configSection.select("Database server type", "dbType", "h2",
+            allowedValues);
+
+    DatabaseConfigInitializer dci =
+        i.getInstance(Key.get(DatabaseConfigInitializer.class,
+            Names.named(dbType.toLowerCase())));
+
+    /** TODO(davido): We probably don't need that, as
+     * CI database would be from the same type as
+     * ReviewDb. So we expect that the needed libraries
+     * were already installed.
+     *
+    if (dci instanceof MySqlInitializer) {
+      libraries.mysqlDriver.downloadRequired();
+    } else if (dci instanceof OracleInitializer) {
+      libraries.oracleDriver.downloadRequired();
+    } else if (dci instanceof DB2Initializer) {
+      libraries.db2Driver.downloadRequired();
+    }
+    **/
+
+    dci.initConfig(configSection);
+  }
+
+  @Override
+  public void postRun() throws Exception {
+    Injector i = buildInjector(parent);
+    updater = i.getProvider(SchemaVersion.class);
+    this.dbFactory = i.getInstance(
+        Key.get(
+            new TypeLiteral<SchemaFactory<CiDb>>() {}));
+    upgradeSchema();
+  }
+
+  private Injector buildInjector(final Injector parent) {
+    List<Module> modules = new ArrayList<>();
+
+    modules.add(new LifecycleModule() {
+      @Override
+      protected void configure() {
+        // For bootstrap we need to retrieve the ds type first
+        CiDataSourceTypeGuesser guesser =
+            parent.createChildInjector(
+                new CiDataSourceModule()).getInstance(
+                    Key.get(CiDataSourceTypeGuesser.class));
+
+        // For the ds type we retrieve the underlying implementation
+        CiDataSourceType dst = parent.createChildInjector(
+            new CiDataSourceModule()).getInstance(
+                Key.get(CiDataSourceType.class,
+                    Names.named(guesser.guessDataSourceType())));
+
+        // Bind the type to the retrieved instance
+        bind(CiDataSourceType.class).toInstance(dst);
+        bind(CiDataSourceProvider.Context.class).toInstance(
+            CiDataSourceProvider.Context.MULTI_USER);
+        bind(Key.get(DataSource.class, Names.named("CiDb"))).toProvider(
+            CiDataSourceProvider.class).in(SINGLETON);
+
+        listener().to(CiDataSourceProvider.class);
+      }
+    });
+
+    modules.add(new CiDatabaseModule());
+
+    modules.add(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(SchemaVersion.class).to(SchemaVersion.C);
+        bind(MetricMaker.class).to(DisabledMetricMaker.class);
+      }
+    });
+
+    return parent.createChildInjector(modules);
+  }
+
+  private void upgradeSchema() throws OrmException {
+    final List<String> pruneList = new ArrayList<>();
+    update(new UpdateUI() {
+      @Override
+      public void message(String msg) {
+        System.err.println(msg);
+        System.err.flush();
+      }
+
+      @Override
+      public boolean yesno(boolean def, String msg) {
+        return ui.yesno(def, msg);
+      }
+
+      @Override
+      public boolean isBatch() {
+        return ui.isBatch();
+      }
+
+      @Override
+      public void pruneSchema(StatementExecutor e, List<String> prune) {
+        for (String p : prune) {
+          if (!pruneList.contains(p)) {
+            pruneList.add(p);
+          }
+        }
+      }
+    });
+
+    if (!pruneList.isEmpty()) {
+      StringBuilder msg = new StringBuilder();
+      msg.append("Execute the following SQL to drop unused objects:\n");
+      msg.append("\n");
+      for (String sql : pruneList) {
+        msg.append("  ");
+        msg.append(sql);
+        msg.append(";\n");
+      }
+
+      if (ui.isBatch()) {
+        System.err.print(msg);
+        System.err.flush();
+
+      } else if (ui.yesno(true, "%s\nExecute now", msg)) {
+        try (JdbcSchema db = (JdbcSchema) dbFactory.open();
+            JdbcExecutor e = new JdbcExecutor(db)) {
+          for (String sql : pruneList) {
+            e.execute(sql);
+          }
+        }
+      }
+    }
+  }
+
+  public void update(UpdateUI ui) throws OrmException {
+    try (CiDb db = dbFactory.open()) {
+      SchemaVersion u = updater.get();
+      CurrentSchemaVersion version = getSchemaVersion(db);
+      if (version == null) {
+          try (JdbcExecutor e = new JdbcExecutor((JdbcSchema) db)) {
+            ((JdbcSchema) db).updateSchema(e);
+          }
+          final CurrentSchemaVersion sVer = CurrentSchemaVersion.create();
+          sVer.versionNbr = SchemaVersion.getBinaryVersion();
+          db.schemaVersion().insert(Collections.singleton(sVer));
+      } else {
+        try {
+          u.check(ui, version, db);
+        } catch (SQLException e) {
+          throw new OrmException("Cannot upgrade schema", e);
+        }
+      }
+    }
+  }
+
+  private CurrentSchemaVersion getSchemaVersion(CiDb db) {
+    try {
+      return db.schemaVersion().get(new CurrentSchemaVersion.Key());
+    } catch (OrmException e) {
+      return null;
+    }
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/MySqlInitializer.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/MySqlInitializer.java
new file mode 100644
index 0000000..f468dcb
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/MySqlInitializer.java
@@ -0,0 +1,32 @@
+// 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.googlesource.gerrit.plugins.ci.init;
+
+import static com.google.gerrit.pgm.init.api.InitUtil.username;
+
+import com.google.gerrit.pgm.init.api.Section;
+
+class MySqlInitializer implements DatabaseConfigInitializer {
+
+  @Override
+  public void initConfig(Section configSection) {
+    final String defPort = "(mysql default)";
+    configSection.string("Server hostname", "hostname", "localhost");
+    configSection.string("Server port", "port", defPort, true);
+    configSection.string("Database name", "database", "cidb");
+    configSection.string("Database username", "username", username());
+    configSection.password("username", "password");
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/OracleInitializer.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/OracleInitializer.java
new file mode 100644
index 0000000..6356d66
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/OracleInitializer.java
@@ -0,0 +1,32 @@
+// Copyright (C) 2013 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.googlesource.gerrit.plugins.ci.init;
+
+import static com.google.gerrit.pgm.init.api.InitUtil.username;
+
+import com.google.gerrit.pgm.init.api.Section;
+
+public class OracleInitializer implements DatabaseConfigInitializer {
+
+  @Override
+  public void initConfig(Section configSection) {
+    final String defPort = "1521";
+    configSection.string("Server hostname", "hostname", "localhost");
+    configSection.string("Server port", "port", defPort, false);
+    configSection.string("Instance name", "instance", "xe");
+    configSection.string("Database username", "username", username());
+    configSection.password("username", "password");
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/init/PostgreSQLInitializer.java b/src/main/java/com/googlesource/gerrit/plugins/ci/init/PostgreSQLInitializer.java
new file mode 100644
index 0000000..200d3c6
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/init/PostgreSQLInitializer.java
@@ -0,0 +1,32 @@
+// 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.googlesource.gerrit.plugins.ci.init;
+
+import static com.google.gerrit.pgm.init.api.InitUtil.username;
+
+import com.google.gerrit.pgm.init.api.Section;
+
+class PostgreSQLInitializer implements DatabaseConfigInitializer {
+
+  @Override
+  public void initConfig(Section configSection) {
+    final String defPort = "(postgresql default)";
+    configSection.string("Server hostname", "hostname", "localhost");
+    configSection.string("Server port", "port", defPort, true);
+    configSection.string("Database name", "database", "cidb");
+    configSection.string("Database username", "username", username());
+    configSection.password("username", "password");
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceModule.java
index 58933fe..33cbd4d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceModule.java
@@ -14,17 +14,17 @@
 
 package com.googlesource.gerrit.plugins.ci.server.schema;
 
-import com.google.inject.AbstractModule;
+import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.inject.name.Names;
 
-public class CiDataSourceModule extends AbstractModule {
+public class CiDataSourceModule extends FactoryModule {
 
   @Override
   protected void configure() {
     bind(CiDataSourceType.class).annotatedWith(Names.named("h2")).to(H2.class);
     bind(CiDataSourceType.class).annotatedWith(Names.named("derby")).to(Derby.class);
-    bind(CiDataSourceType.class).annotatedWith(Names.named("mysql")).to(MySql.class);
-    bind(CiDataSourceType.class).annotatedWith(Names.named("oracle")).to(Oracle.class);
-    bind(CiDataSourceType.class).annotatedWith(Names.named("postgresql")).to(PostgreSQL.class);
+//    bind(CiDataSourceType.class).annotatedWith(Names.named("mysql")).to(MySql.class);
+//    bind(CiDataSourceType.class).annotatedWith(Names.named("oracle")).to(Oracle.class);
+//    bind(CiDataSourceType.class).annotatedWith(Names.named("postgresql")).to(PostgreSQL.class);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceProvider.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceProvider.java
index 1a24291..9cbf1ef 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceProvider.java
@@ -17,17 +17,8 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.sql.SQLException;
-import java.util.Properties;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.eclipse.jgit.lib.Config;
-
 import com.google.common.base.Strings;
+import com.google.gerrit.common.Nullable;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.extensions.persistence.DataSourceInterceptor;
@@ -35,34 +26,55 @@
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.Field;
 import com.google.gerrit.metrics.MetricMaker;
-import com.google.gerrit.server.config.ConfigSection;
 import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.config.PluginConfig;
+import com.google.gerrit.server.config.SitePaths;
 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.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
 /** Provides access to the DataSource. */
 @Singleton
 public class CiDataSourceProvider implements Provider<DataSource>,
     LifecycleListener {
   public static final int DEFAULT_POOL_LIMIT = 8;
 
-  private final Config cfg;
   private final MetricMaker metrics;
   private final Context ctx;
   private final CiDataSourceType dst;
+  private final PluginConfig config;
   private DataSource ds;
 
   @Inject
-  protected CiDataSourceProvider(PluginConfigFactory cfgFactory,
+  protected CiDataSourceProvider(SitePaths site,
       @PluginName String pluginName,
-      MetricMaker metrics,
+      @Nullable MetricMaker metrics,
       Context ctx,
       CiDataSourceType dst) {
-    this.cfg = cfgFactory.getGlobalPluginConfig(pluginName);
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
+    }
+    this.config = new PluginConfig(pluginName, cfg);
     this.metrics = metrics;
     this.ctx = ctx;
     this.dst = dst;
@@ -71,7 +83,7 @@
   @Override
   public synchronized DataSource get() {
     if (ds == null) {
-      ds = open(cfg, ctx, dst);
+      ds = open(ctx, dst);
     }
     return ds;
   }
@@ -95,27 +107,27 @@
     SINGLE_USER, MULTI_USER
   }
 
-  private DataSource open(Config cfg, Context context, CiDataSourceType dst) {
-    ConfigSection dbs = new ConfigSection(cfg, "database");
-    String driver = dbs.optional("driver");
+  private DataSource open(Context context, CiDataSourceType dst) {
+    //ConfigSection dbs = new ConfigSection(cfg, "database");
+    String driver = config.getString("driver");
     if (Strings.isNullOrEmpty(driver)) {
       driver = dst.getDriver();
     }
 
-    String url = dbs.optional("url");
+    String url = config.getString("dbUrl");
     if (Strings.isNullOrEmpty(url)) {
       url = dst.getUrl();
     }
 
-    String username = dbs.optional("username");
-    String password = dbs.optional("password");
-    String interceptor = dbs.optional("dataSourceInterceptorClass");
+    String username = config.getString("username");
+    String password = config.getString("password");
+    String interceptor = config.getString("dataSourceInterceptorClass");
 
     boolean usePool;
     if (context == Context.SINGLE_USER) {
       usePool = false;
     } else {
-      usePool = cfg.getBoolean("database", "connectionpool", dst.usePool());
+      usePool = config.getBoolean("connectionpool", dst.usePool());
     }
 
     if (usePool) {
@@ -128,15 +140,19 @@
       if (password != null && !password.isEmpty()) {
         ds.setPassword(password);
       }
-      ds.setMaxActive(cfg.getInt("database", "poollimit", DEFAULT_POOL_LIMIT));
-      ds.setMinIdle(cfg.getInt("database", "poolminidle", 4));
-      ds.setMaxIdle(cfg.getInt("database", "poolmaxidle", 4));
-      ds.setMaxWait(ConfigUtil.getTimeUnit(cfg, "database", null,
-          "poolmaxwait", MILLISECONDS.convert(30, SECONDS), MILLISECONDS));
+      ds.setMaxActive(config.getInt("poollimit", DEFAULT_POOL_LIMIT));
+      ds.setMinIdle(config.getInt("poolminidle", 4));
+      ds.setMaxIdle(config.getInt("poolmaxidle", 4));
+      String valueString = config.getString("poolmaxwait");
+      if (Strings.isNullOrEmpty(valueString)) {
+        ds.setMaxWait(MILLISECONDS.convert(30, SECONDS));
+      } else {
+        ds.setMaxWait(ConfigUtil.getTimeUnit(
+            valueString, MILLISECONDS.convert(30, SECONDS), MILLISECONDS));
+      }
       ds.setInitialSize(ds.getMinIdle());
       exportPoolMetrics(ds);
       return intercept(interceptor, ds);
-
     } else {
       // Don't use the connection pool.
       //
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceTypeGuesser.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceTypeGuesser.java
index 8417304..6dc70ae 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceTypeGuesser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDataSourceTypeGuesser.java
@@ -14,41 +14,42 @@
 
 package com.googlesource.gerrit.plugins.ci.server.schema;
 
-import java.nio.file.Path;
-
-import org.eclipse.jgit.lib.Config;
-
 import com.google.common.base.Strings;
 import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
 import com.google.inject.ProvisionException;
 
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+import java.io.File;
+import java.io.IOException;
+
 public class CiDataSourceTypeGuesser {
 
-  private final Config cfg;
-  private final String configFile;
+  private final PluginConfig config;
 
   @Inject
   CiDataSourceTypeGuesser(SitePaths site,
-      PluginConfigFactory pluginConfig,
       @PluginName String pluginName) {
-    this.cfg = pluginConfig.getGlobalPluginConfig(pluginName);
-    configFile = String.format("%s.config", pluginName);
-    Path config = site.resolve("etc").resolve(configFile);
-    if (!config.toFile().exists()) {
-      throw new ProvisionException(
-          String.format("Config file %s for plugin %s doesn't exist",
-              configFile, pluginName));
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
     }
+    this.config = new PluginConfig(pluginName, cfg);
   }
 
   public String guessDataSourceType() {
-    String dbType = cfg.getString("database", null, "type");
+    String dbType = config.getString("dbType");
     if (Strings.isNullOrEmpty(dbType)) {
       throw new ProvisionException(
-          String.format("'database.type' must be defined in: %s", configFile));
+          String.format("'dbType' must be defined in config file"));
     }
     return dbType.toLowerCase();
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDatabaseModule.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDatabaseModule.java
index 49c7b66..8a98bb4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDatabaseModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/CiDatabaseModule.java
@@ -20,6 +20,7 @@
 import com.google.gwtorm.jdbc.Database;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.TypeLiteral;
+
 import com.googlesource.gerrit.plugins.ci.server.CiDb;
 
 /** Loads the database with standard dependencies. */
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Derby.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Derby.java
index f89662e..4ec7d95 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Derby.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Derby.java
@@ -15,32 +15,43 @@
 package com.googlesource.gerrit.plugins.ci.server.schema;
 
 import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
+import com.google.inject.ProvisionException;
 
-import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+import java.io.File;
+import java.io.IOException;
 
 class Derby extends CiBaseDataSourceType {
-
-  private final Config cfg;
   private final SitePaths site;
+  private final PluginConfig config;
 
   @Inject
   Derby(SitePaths site,
-      PluginConfigFactory pluginConfig,
       @PluginName String pluginName) {
     super("org.apache.derby.jdbc.EmbeddedDriver");
-    this.cfg = pluginConfig.getGlobalPluginConfig(pluginName);
     this.site = site;
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
+    }
+    this.config = new PluginConfig(pluginName, cfg);
   }
 
   @Override
   public String getUrl() {
-    String database = cfg.getString("database", null, "database");
-    if (database == null || database.isEmpty()) {
-      database = "db/CiDB";
+    String db = config.getString("database");
+    if (db == null || db.isEmpty()) {
+      db = "db/CiDB";
     }
-    return "jdbc:derby:" + site.resolve(database).toString() + ";create=true";
+    return "jdbc:derby:" + site.resolve(db).toString() + ";create=true";
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/H2.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/H2.java
index 7d29865..32d06c8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/H2.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/H2.java
@@ -14,33 +14,44 @@
 
 package com.googlesource.gerrit.plugins.ci.server.schema;
 
-import org.eclipse.jgit.lib.Config;
-
 import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
+import com.google.inject.ProvisionException;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+import java.io.File;
+import java.io.IOException;
 
 class H2 extends CiBaseDataSourceType {
-
-  private final Config cfg;
   private final SitePaths site;
+  private final PluginConfig config;
 
   @Inject
   H2(SitePaths site,
-      PluginConfigFactory pluginConfig,
       @PluginName String pluginName) {
     super("org.h2.Driver");
-    this.cfg = pluginConfig.getGlobalPluginConfig(pluginName);
     this.site = site;
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
+    }
+    this.config = new PluginConfig(pluginName, cfg);
   }
 
   @Override
   public String getUrl() {
-    String database = cfg.getString("database", null, "database");
-    if (database == null || database.isEmpty()) {
-      database = "db/CiDB";
+    String db = config.getString("database");
+    if (db == null || db.isEmpty()) {
+      db = "db/CiDB";
     }
-    return "jdbc:h2:" + site.resolve(database).toUri().toString();
+    return "jdbc:h2:" + site.resolve(db).toUri().toString();
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/MySql.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/MySql.java
index b5ad309..219fd59 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/MySql.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/MySql.java
@@ -17,31 +17,44 @@
 import static com.google.gerrit.server.schema.JdbcUtil.hostname;
 import static com.google.gerrit.server.schema.JdbcUtil.port;
 
-import com.google.gerrit.server.config.ConfigSection;
-import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.PluginConfig;
+import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
+import com.google.inject.ProvisionException;
 
-import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+import java.io.File;
+import java.io.IOException;
 
 class MySql extends CiBaseDataSourceType {
-
-  private Config cfg;
+  private final PluginConfig config;
 
   @Inject
-  public MySql(@GerritServerConfig final Config cfg) {
+  public MySql(SitePaths site,
+      @PluginName String pluginName) {
     super("com.mysql.jdbc.Driver");
-    this.cfg = cfg;
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
+    }
+    this.config = new PluginConfig(pluginName, cfg);
   }
 
   @Override
   public String getUrl() {
     final StringBuilder b = new StringBuilder();
-    final ConfigSection dbs = new ConfigSection(cfg, "database");
     b.append("jdbc:mysql://");
-    b.append(hostname(dbs.optional("hostname")));
-    b.append(port(dbs.optional("port")));
+    b.append(hostname(config.getString("hostname")));
+    b.append(port(config.getString("port")));
     b.append("/");
-    b.append(dbs.required("database"));
+    b.append(config.getString("database"));
     return b.toString();
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Oracle.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Oracle.java
index ce766a4..1f14ae1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Oracle.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Oracle.java
@@ -17,30 +17,44 @@
 import static com.google.gerrit.server.schema.JdbcUtil.hostname;
 import static com.google.gerrit.server.schema.JdbcUtil.port;
 
-import com.google.gerrit.server.config.ConfigSection;
-import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.PluginConfig;
+import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
+import com.google.inject.ProvisionException;
 
-import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+import java.io.File;
+import java.io.IOException;
 
 public class Oracle extends CiBaseDataSourceType {
-  private Config cfg;
+  private final PluginConfig config;
 
   @Inject
-  public Oracle(@GerritServerConfig Config cfg) {
+  public Oracle(SitePaths site,
+      @PluginName String pluginName) {
     super("oracle.jdbc.driver.OracleDriver");
-    this.cfg = cfg;
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
+    }
+    this.config = new PluginConfig(pluginName, cfg);
   }
 
   @Override
   public String getUrl() {
     final StringBuilder b = new StringBuilder();
-    final ConfigSection dbc = new ConfigSection(cfg, "database");
     b.append("jdbc:oracle:thin:@");
-    b.append(hostname(dbc.optional("hostname")));
-    b.append(port(dbc.optional("port")));
+    b.append(hostname(config.getString("hostname")));
+    b.append(port(config.getString("port")));
     b.append(":");
-    b.append(dbc.required("instance"));
+    b.append(config.getString("instance"));
     return b.toString();
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/PostgreSQL.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/PostgreSQL.java
index ed41857..46eb036 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/PostgreSQL.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/PostgreSQL.java
@@ -17,38 +17,44 @@
 import static com.google.gerrit.server.schema.JdbcUtil.hostname;
 import static com.google.gerrit.server.schema.JdbcUtil.port;
 
-import com.google.gerrit.server.config.ConfigSection;
-import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.server.config.PluginConfig;
+import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
+import com.google.inject.ProvisionException;
 
-import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 
+import java.io.File;
 import java.io.IOException;
 
 class PostgreSQL extends CiBaseDataSourceType {
-
-  private Config cfg;
+  private final PluginConfig config;
 
   @Inject
-  public PostgreSQL(@GerritServerConfig Config cfg) {
+  public PostgreSQL(SitePaths site,
+      @PluginName String pluginName) {
     super("org.postgresql.Driver");
-    this.cfg = cfg;
+    File file = site.gerrit_config.toFile();
+    FileBasedConfig cfg = new FileBasedConfig(file, FS.DETECTED);
+    try {
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new ProvisionException(e.getMessage(), e);
+    }
+    this.config = new PluginConfig(pluginName, cfg);
   }
 
   @Override
   public String getUrl() {
     final StringBuilder b = new StringBuilder();
-    final ConfigSection dbc = new ConfigSection(cfg, "database");
     b.append("jdbc:postgresql://");
-    b.append(hostname(dbc.optional("hostname")));
-    b.append(port(dbc.optional("port")));
+    b.append(hostname(config.getString("hostname")));
+    b.append(port(config.getString("port")));
     b.append("/");
-    b.append(dbc.required("database"));
+    b.append(config.getString("database"));
     return b.toString();
   }
-
-  @Override
-  public ScriptRunner getIndexScript() throws IOException {
-    return getScriptRunner("index_postgres.sql");
-  }
 }
\ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/SchemaVersion.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/SchemaVersion.java
index 1517824..cf929cf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/SchemaVersion.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/SchemaVersion.java
@@ -23,6 +23,8 @@
 import com.google.gwtorm.server.StatementExecutor;
 import com.google.inject.Provider;
 
+import com.googlesource.gerrit.plugins.ci.server.CiDb;
+
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
 import java.sql.Statement;
@@ -60,7 +62,7 @@
     return versionNbr;
   }
 
-  public final void check(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db)
+  public final void check(UpdateUI ui, CurrentSchemaVersion curr, CiDb db)
       throws OrmException, SQLException {
     if (curr.versionNbr == versionNbr) {
       // Nothing to do, we are at the correct schema.
@@ -73,7 +75,7 @@
   }
 
   /** Runs check on the prior schema version, and then upgrades. */
-  private void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db)
+  private void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr, CiDb db)
       throws OrmException, SQLException {
     List<SchemaVersion> pending = pending(curr.versionNbr);
     updateSchema(pending, ui, db);
@@ -110,7 +112,7 @@
   }
 
   private void updateSchema(List<SchemaVersion> pending, UpdateUI ui,
-      ReviewDb db) throws OrmException, SQLException {
+      CiDb db) throws OrmException, SQLException {
     for (SchemaVersion v : pending) {
       ui.message(String.format("Upgrading schema to %d ...", v.getVersionNbr()));
       v.preUpdateSchema(db);
@@ -129,11 +131,11 @@
    * @throws OrmException if a Gerrit-specific exception occurred.
    * @throws SQLException if an underlying SQL exception occurred.
    */
-  protected void preUpdateSchema(ReviewDb db) throws OrmException, SQLException {
+  protected void preUpdateSchema(CiDb db) throws OrmException, SQLException {
   }
 
   private void migrateData(List<SchemaVersion> pending, UpdateUI ui,
-      CurrentSchemaVersion curr, ReviewDb db) throws OrmException, SQLException {
+      CurrentSchemaVersion curr, CiDb db) throws OrmException, SQLException {
     for (SchemaVersion v : pending) {
       ui.message(String.format(
           "Migrating data to schema %d ...",
@@ -152,11 +154,11 @@
    * @throws OrmException if a Gerrit-specific exception occurred.
    * @throws SQLException if an underlying SQL exception occurred.
    */
-  protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException, SQLException {
+  protected void migrateData(CiDb db, UpdateUI ui) throws OrmException, SQLException {
   }
 
   /** Mark the current schema version. */
-  protected void finish(CurrentSchemaVersion curr, ReviewDb db)
+  protected void finish(CurrentSchemaVersion curr, CiDb db)
       throws OrmException {
     curr.versionNbr = versionNbr;
     db.schemaVersion().update(Collections.singleton(curr));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Schema_1.java b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Schema_1.java
index d4620ac..cc5adcf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Schema_1.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/ci/server/schema/Schema_1.java
@@ -14,7 +14,6 @@
 
 package com.googlesource.gerrit.plugins.ci.server.schema;
 
-import com.google.gerrit.server.schema.SchemaVersion;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;