Merge "Update 2.6 release notes with more trivial_rebase fixes" into stable-2.6
diff --git a/ReleaseNotes/ReleaseNotes-2.6.txt b/ReleaseNotes/ReleaseNotes-2.6.txt
index e293936..85f2844 100644
--- a/ReleaseNotes/ReleaseNotes-2.6.txt
+++ b/ReleaseNotes/ReleaseNotes-2.6.txt
@@ -427,11 +427,12 @@
 HTML thanks to Gson encoding HTML control characters using Unicode
 character escapes within JSON strings.
 
-* Apache reverse proxies need `AllowEncodedSlashes NoDecode`
+* Apache reverse proxies must switch to mod_rewrite
 +
-When Apache is used as a reverse proxy the NoDecode option
-must be set for AllowEncodedSlashes to prevent Apache from
-mangling Gerrit REST API URLs.
+When Apache is used as a reverse proxy the server must be reconfigured
+to use mod_rewrite and AllowEncodedSlashes.  For updated information
+link:http://gerrit-documentation.googlecode.com/svn/Documentation/2.6/config-reverseproxy.html#_apache_2_configuration[
+review the Apache 2 Configuration documentation].
 
 Project Dashboards
 ~~~~~~~~~~~~~~~~~~
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index 932f8f0..28e361c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -173,7 +173,7 @@
         String displayName;
         if (a.getUserName() != null) {
           displayName = a.getUserName();
-        } else if (a.getFullName() != null) {
+        } else if (a.getFullName() != null && !a.getFullName().isEmpty()) {
           displayName = a.getFullName();
         } else if (a.getPreferredEmail() != null) {
           displayName = a.getPreferredEmail();
diff --git a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html
index 3548b9a..c660311 100644
--- a/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html
+++ b/gerrit-httpd/src/main/resources/com/google/gerrit/httpd/auth/become/BecomeAnyAccount.html
@@ -68,7 +68,7 @@
         </tr>
 
         <tr>
-          <th>Choose:</th>
+          <th style="vertical-align: top;">Choose:</th>
           <td id="userlist"/>
         </tr>
       </table>
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
index c0f0c4b..3c7822c 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Init.java
@@ -21,7 +21,6 @@
 import com.google.gerrit.pgm.init.Browser;
 import com.google.gerrit.pgm.init.InitFlags;
 import com.google.gerrit.pgm.init.InitModule;
-import com.google.gerrit.pgm.init.ReloadSiteLibrary;
 import com.google.gerrit.pgm.init.SitePathInitializer;
 import com.google.gerrit.pgm.util.ConsoleUI;
 import com.google.gerrit.pgm.util.Die;
@@ -121,12 +120,6 @@
       protected void configure() {
         bind(ConsoleUI.class).toInstance(ui);
         bind(File.class).annotatedWith(SitePath.class).toInstance(sitePath);
-        bind(ReloadSiteLibrary.class).toInstance(new ReloadSiteLibrary() {
-          @Override
-          public void reload() {
-            Init.super.loadSiteLib();
-          }
-        });
       }
     });
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java
index 4ce963a..0336dda 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitDatabase.java
@@ -16,6 +16,8 @@
 
 import static com.google.inject.Stage.PRODUCTION;
 
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
 import com.google.gerrit.pgm.util.ConsoleUI;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Binding;
@@ -53,7 +55,7 @@
   public void run() {
     ui.header("SQL Database");
 
-    Set<String> allowedValues = new TreeSet<String>();
+    Set<String> allowedValues = Sets.newTreeSet();
     Injector i = Guice.createInjector(PRODUCTION, new DatabaseConfigModule(site));
     List<Binding<DatabaseConfigInitializer>> dbConfigBindings =
         i.findBindingsByType(new TypeLiteral<DatabaseConfigInitializer>() {});
@@ -64,6 +66,11 @@
       }
     }
 
+    if (!Strings.isNullOrEmpty(database.get("url"))
+        && Strings.isNullOrEmpty(database.get("type"))) {
+      database.set("type", "jdbc");
+    }
+
     String dbType =
         database.select("Database server type", "type", "h2", allowedValues);
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
index ff1eddf..b1fa0c3 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/Libraries.java
@@ -78,6 +78,7 @@
     dl.setName(get(cfg, n, "name"));
     dl.setJarUrl(get(cfg, n, "url"));
     dl.setSHA1(get(cfg, n, "sha1"));
+    dl.setRemove(get(cfg, n, "remove"));
     field.set(this, dl);
   }
 
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
index ea1b515..bf358f4 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/LibraryDownloader.java
@@ -14,8 +14,10 @@
 
 package com.google.gerrit.pgm.init;
 
+import com.google.common.base.Strings;
 import com.google.gerrit.pgm.util.ConsoleUI;
 import com.google.gerrit.pgm.util.Die;
+import com.google.gerrit.pgm.util.IoUtil;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
 
@@ -26,6 +28,7 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -40,20 +43,18 @@
 class LibraryDownloader {
   private final ConsoleUI ui;
   private final File lib_dir;
-  private final ReloadSiteLibrary reload;
 
   private boolean required;
   private String name;
   private String jarUrl;
   private String sha1;
+  private String remove;
   private File dst;
 
   @Inject
-  LibraryDownloader(final ReloadSiteLibrary reload, final ConsoleUI ui,
-      final SitePaths site) {
+  LibraryDownloader(ConsoleUI ui, SitePaths site) {
     this.ui = ui;
     this.lib_dir = site.lib_dir;
-    this.reload = reload;
   }
 
   void setName(final String name) {
@@ -68,6 +69,10 @@
     this.sha1 = sha1;
   }
 
+  void setRemove(String remove) {
+    this.remove = remove;
+  }
+
   void downloadRequired() {
     this.required = true;
     download();
@@ -123,6 +128,7 @@
     }
 
     try {
+      removeStaleVersions();
       doGetByHttp();
       verifyFileChecksum();
     } catch (IOException err) {
@@ -155,7 +161,29 @@
       }
     }
 
-    reload.reload();
+    if (dst.exists()) {
+      IoUtil.loadJARs(dst);
+    }
+  }
+
+  private void removeStaleVersions() {
+    if (!Strings.isNullOrEmpty(remove)) {
+      String[] names = lib_dir.list(new FilenameFilter() {
+        @Override
+        public boolean accept(File dir, String name) {
+          return name.matches("^" + remove + "$");
+        }
+      });
+      if (names != null) {
+        for (String old : names) {
+          String bak = "." + old + ".backup";
+          ui.message("Renaming %s to %s", old, bak);
+          if (!new File(lib_dir, old).renameTo(new File(lib_dir, bak))) {
+            throw new Die("cannot rename " + old);
+          }
+        }
+      }
+    }
   }
 
   private void doGetByHttp() throws IOException {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/ReloadSiteLibrary.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/ReloadSiteLibrary.java
deleted file mode 100644
index b21d3c0..0000000
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/ReloadSiteLibrary.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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.init;
-
-/** Requests the site's {@code lib/} directory be scanned again. */
-public interface ReloadSiteLibrary {
-  public void reload();
-}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/IoUtil.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/IoUtil.java
index 9398851..f750748a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/IoUtil.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/IoUtil.java
@@ -14,9 +14,19 @@
 
 package com.google.gerrit.pgm.util;
 
+import com.google.common.collect.Sets;
+
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Set;
 
 public final class IoUtil {
   public static void copyWithThread(final InputStream src,
@@ -42,6 +52,47 @@
     }.start();
   }
 
+  public static void loadJARs(File... jars) {
+    ClassLoader cl = IoUtil.class.getClassLoader();
+    if (!(cl instanceof URLClassLoader)) {
+      throw noAddURL("Not loaded by URLClassLoader", null);
+    }
+    @SuppressWarnings("resource")
+    URLClassLoader urlClassLoader = (URLClassLoader) cl;
+
+    Method addURL;
+    try {
+      addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+      addURL.setAccessible(true);
+    } catch (SecurityException e) {
+      throw noAddURL("Method addURL not available", e);
+    } catch (NoSuchMethodException e) {
+      throw noAddURL("Method addURL not available", e);
+    }
+
+    Set<URL> have = Sets.newHashSet(Arrays.asList(urlClassLoader.getURLs()));
+    for (File path : jars) {
+      try {
+        URL url = path.toURI().toURL();
+        if (have.add(url)) {
+          addURL.invoke(cl, url);
+        }
+      } catch (MalformedURLException e) {
+        throw noAddURL("addURL " + path + " failed", e);
+      } catch (IllegalArgumentException e) {
+        throw noAddURL("addURL " + path + " failed", e);
+      } catch (IllegalAccessException e) {
+        throw noAddURL("addURL " + path + " failed", e);
+      } catch (InvocationTargetException e) {
+        throw noAddURL("addURL " + path + " failed", e.getCause());
+      }
+    }
+  }
+
+  private static UnsupportedOperationException noAddURL(String m, Throwable why) {
+    String prefix = "Cannot extend classpath: ";
+    return new UnsupportedOperationException(prefix + m, why);
+  }
   private IoUtil() {
   }
 }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java
new file mode 100644
index 0000000..6ab7395
--- /dev/null
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteLibraryBasedDataSourceProvider.java
@@ -0,0 +1,81 @@
+// 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.google.gerrit.pgm.util;
+
+import com.google.common.primitives.Longs;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.schema.DataSourceProvider;
+import com.google.gerrit.server.schema.DataSourceType;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import org.eclipse.jgit.lib.Config;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import javax.sql.DataSource;
+
+/** Loads the site library if not yet loaded. */
+@Singleton
+public class SiteLibraryBasedDataSourceProvider extends DataSourceProvider {
+  private final File libdir;
+  private boolean init;
+
+  @Inject
+  SiteLibraryBasedDataSourceProvider(SitePaths site,
+      @GerritServerConfig Config cfg,
+      DataSourceProvider.Context ctx,
+      DataSourceType dst) {
+    super(site, cfg, ctx, dst);
+    libdir = site.lib_dir;
+  }
+
+  public synchronized DataSource get() {
+    if (!init) {
+      loadSiteLib();
+      init = true;
+    }
+    return super.get();
+  }
+
+  private void loadSiteLib() {
+    File[] jars = libdir.listFiles(new FileFilter() {
+      @Override
+      public boolean accept(File path) {
+        String name = path.getName();
+        return (name.endsWith(".jar") || name.endsWith(".zip"))
+            && path.isFile();
+      }
+    });
+    if (jars != null && 0 < jars.length) {
+      Arrays.sort(jars, new Comparator<File>() {
+        @Override
+        public int compare(File a, File b) {
+          // Sort by reverse last-modified time so newer JARs are first.
+          int cmp = Longs.compare(b.lastModified(), a.lastModified());
+          if (cmp != 0) {
+            return cmp;
+          }
+          return a.getName().compareTo(b.getName());
+        }
+      });
+      IoUtil.loadJARs(jars);
+    }
+  }
+}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
index 242ca28..aae5b48 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -41,19 +41,9 @@
 import org.kohsuke.args4j.Option;
 
 import java.io.File;
-import java.io.FileFilter;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
 import java.sql.SQLException;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 import javax.sql.DataSource;
 
@@ -78,77 +68,8 @@
     }
   }
 
-  /** Load extra JARs from {@code lib/} subdirectory of {@link #getSitePath()} */
-  protected void loadSiteLib() {
-    final File libdir = new File(getSitePath(), "lib");
-    final File[] list = libdir.listFiles(new FileFilter() {
-      @Override
-      public boolean accept(File path) {
-        if (!path.isFile()) {
-          return false;
-        }
-        return path.getName().endsWith(".jar") //
-            || path.getName().endsWith(".zip");
-      }
-    });
-    if (list != null && 0 < list.length) {
-      Arrays.sort(list, new Comparator<File>() {
-        @Override
-        public int compare(File a, File b) {
-          return a.getName().compareTo(b.getName());
-        }
-      });
-      addToClassLoader(list);
-    }
-  }
-
-  private void addToClassLoader(final File[] additionalLocations) {
-    final ClassLoader cl = getClass().getClassLoader();
-    if (!(cl instanceof URLClassLoader)) {
-      throw noAddURL("Not loaded by URLClassLoader", null);
-    }
-
-    final URLClassLoader ucl = (URLClassLoader) cl;
-    final Set<URL> have = new HashSet<URL>();
-    have.addAll(Arrays.asList(ucl.getURLs()));
-
-    final Method m;
-    try {
-      m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
-      m.setAccessible(true);
-    } catch (SecurityException e) {
-      throw noAddURL("Method addURL not available", e);
-    } catch (NoSuchMethodException e) {
-      throw noAddURL("Method addURL not available", e);
-    }
-
-    for (final File path : additionalLocations) {
-      try {
-        final URL url = path.toURI().toURL();
-        if (have.add(url)) {
-          m.invoke(cl, url);
-        }
-      } catch (MalformedURLException e) {
-        throw noAddURL("addURL " + path + " failed", e);
-      } catch (IllegalArgumentException e) {
-        throw noAddURL("addURL " + path + " failed", e);
-      } catch (IllegalAccessException e) {
-        throw noAddURL("addURL " + path + " failed", e);
-      } catch (InvocationTargetException e) {
-        throw noAddURL("addURL " + path + " failed", e.getCause());
-      }
-    }
-  }
-
-  private static UnsupportedOperationException noAddURL(String m, Throwable why) {
-    final String prefix = "Cannot extend classpath: ";
-    return new UnsupportedOperationException(prefix + m, why);
-  }
-
   /** @return provides database connectivity and site path. */
   protected Injector createDbInjector(final DataSourceProvider.Context context) {
-    loadSiteLib();
-
     final File sitePath = getSitePath();
     final List<Module> modules = new ArrayList<Module>();
 
@@ -164,9 +85,10 @@
       @Override
       protected void configure() {
         bind(DataSourceProvider.Context.class).toInstance(context);
-        bind(Key.get(DataSource.class, Names.named("ReviewDb"))).toProvider(
-            DataSourceProvider.class).in(SINGLETON);
-        listener().to(DataSourceProvider.class);
+        bind(Key.get(DataSource.class, Names.named("ReviewDb")))
+          .toProvider(SiteLibraryBasedDataSourceProvider.class)
+          .in(SINGLETON);
+        listener().to(SiteLibraryBasedDataSourceProvider.class);
       }
     });
     Module configModule = new GerritServerConfigModule();
diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
index f4c5808..f1ecadd 100644
--- a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
+++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/libraries.config
@@ -17,8 +17,10 @@
   name = Bouncy Castle Crypto v144
   url = http://www.bouncycastle.org/download/bcprov-jdk16-144.jar
   sha1 = 6327a5f7a3dc45e0fd735adb5d08c5a74c05c20c
+  remove = bcprov-.*[.]jar
 
 [library "mysqlDriver"]
   name = MySQL Connector/J 5.1.21
   url = http://repo2.maven.org/maven2/mysql/mysql-connector-java/5.1.21/mysql-connector-java-5.1.21.jar
   sha1 = 7abbd19fc2e2d5b92c0895af8520f7fa30266be9
+  remove = mysql-connector-java-.*[.]jar
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
index e723463..df1f447 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/LibrariesTest.java
@@ -30,16 +30,14 @@
 public class LibrariesTest extends TestCase {
   public void testCreate() throws FileNotFoundException {
     final SitePaths site = new SitePaths(new File("."));
-    final ReloadSiteLibrary reload = createStrictMock(ReloadSiteLibrary.class);
     final ConsoleUI ui = createStrictMock(ConsoleUI.class);
 
     replay(ui);
-    replay(reload);
 
     Libraries lib = new Libraries(new Provider<LibraryDownloader>() {
       @Override
       public LibraryDownloader get() {
-        return new LibraryDownloader(reload, ui, site);
+        return new LibraryDownloader(ui, site);
       }
     });
 
@@ -47,6 +45,5 @@
     assertNotNull(lib.mysqlDriver);
 
     verify(ui);
-    verify(reload);
   }
 }
diff --git a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
index 80ea82f..94b37e1 100644
--- a/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
+++ b/gerrit-reviewdb/src/main/java/com/google/gerrit/reviewdb/client/Account.java
@@ -169,7 +169,11 @@
 
   /** Set the full name of the user ("Given-name Surname" style). */
   public void setFullName(final String name) {
-    fullName = name != null ? name.trim() : null;
+    if (name != null && !name.trim().isEmpty()) {
+      fullName = name.trim();
+    } else {
+      fullName = null;
+    }
   }
 
   /** Email address the user prefers to be contacted through. */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
index 0c54883..6c9ca59d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/DataSourceProvider.java
@@ -39,18 +39,30 @@
 
 /** Provides access to the DataSource. */
 @Singleton
-public final class DataSourceProvider implements Provider<DataSource>,
+public class DataSourceProvider implements Provider<DataSource>,
     LifecycleListener {
-  private final DataSource ds;
+  private final SitePaths site;
+  private final Config cfg;
+  private final Context ctx;
+  private final DataSourceType dst;
+  private DataSource ds;
 
   @Inject
-  DataSourceProvider(final SitePaths site,
-      @GerritServerConfig final Config cfg, Context ctx, DataSourceType dst) {
-    ds = open(site, cfg, ctx, dst);
+  protected DataSourceProvider(SitePaths site,
+      @GerritServerConfig Config cfg,
+      Context ctx,
+      DataSourceType dst) {
+    this.site = site;
+    this.cfg = cfg;
+    this.ctx = ctx;
+    this.dst = dst;
   }
 
   @Override
   public synchronized DataSource get() {
+    if (ds == null) {
+      ds = open(site, cfg, ctx, dst);
+    }
     return ds;
   }