Merge changes I8596041e,I373db466

* changes:
  Extract a minimal interface for contactstore connections
  Initialize BouncyCastleProvider when checking for PGP.
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 5a29044..def3aed 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
@@ -34,6 +34,7 @@
 import com.google.gerrit.server.config.CanonicalWebUrlProvider;
 import com.google.gerrit.server.config.GerritGlobalModule;
 import com.google.gerrit.server.config.MasterNodeStartup;
+import com.google.gerrit.server.contact.HttpContactStoreConnection;
 import com.google.gerrit.server.git.PushReplication;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.SmtpEmailSender;
@@ -253,6 +254,7 @@
     modules.add(sysInjector.getInstance(GitOverHttpModule.class));
     modules.add(sshInjector.getInstance(WebSshGlueModule.class));
     modules.add(CacheBasedWebSession.module());
+    modules.add(HttpContactStoreConnection.module());
     if (sshd) {
       modules.add(sshInjector.getInstance(ProjectQoSFilter.Module.class));
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreConnection.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreConnection.java
new file mode 100644
index 0000000..24c9e66
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreConnection.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2011 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.contact;
+
+import java.io.IOException;
+import java.net.URL;
+
+/** Single connection to a {@link ContactStore}. */
+public interface ContactStoreConnection {
+  public static interface Factory {
+    /**
+     * Open a new connection to a {@link ContactStore}.
+     *
+     * @param url contact store URL.
+     * @return a new connection to the store.
+     *
+     * @throws IOException the URL couldn't be opened.
+     */
+    ContactStoreConnection open(URL url) throws IOException;
+  }
+
+  /**
+   * Store a blob of contact data in the store.
+   *
+   * @param body protocol-specific body data.
+   *
+   * @throws IOException an error occurred storing the contact data.
+   */
+  public void store(byte[] body) throws IOException;
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java
index da17c08..e3b8ea7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/ContactStoreProvider.java
@@ -22,25 +22,30 @@
 import com.google.inject.Provider;
 import com.google.inject.ProvisionException;
 
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.openpgp.PGPPublicKey;
 import org.eclipse.jgit.lib.Config;
 
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.security.Security;
 
 /** Creates the {@link ContactStore} based on the configuration. */
 public class ContactStoreProvider implements Provider<ContactStore> {
   private final Config config;
   private final SitePaths site;
   private final SchemaFactory<ReviewDb> schema;
+  private final ContactStoreConnection.Factory connFactory;
 
   @Inject
   ContactStoreProvider(@GerritServerConfig final Config config,
-      final SitePaths site, final SchemaFactory<ReviewDb> schema) {
+      final SitePaths site, final SchemaFactory<ReviewDb> schema,
+      final ContactStoreConnection.Factory connFactory) {
     this.config = config;
     this.site = site;
     this.schema = schema;
+    this.connFactory = connFactory;
   }
 
   @Override
@@ -68,12 +73,14 @@
       throw new ProvisionException("PGP public key file \""
           + pubkey.getAbsolutePath() + "\" not found");
     }
-    return new EncryptedContactStore(storeUrl, storeAPPSEC, pubkey, schema);
+    return new EncryptedContactStore(storeUrl, storeAPPSEC, pubkey, schema,
+        connFactory);
   }
 
   private static boolean havePGP() {
     try {
       Class.forName(PGPPublicKey.class.getName());
+      Security.addProvider(new BouncyCastleProvider());
       return true;
     } catch (NoClassDefFoundError noBouncyCastle) {
       return false;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
index 05d4e7a..d391694 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/EncryptedContactStore.java
@@ -37,7 +37,6 @@
 import org.bouncycastle.openpgp.PGPPublicKeyRing;
 import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
 import org.bouncycastle.openpgp.PGPUtil;
-import org.eclipse.jgit.util.IO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,7 +46,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.HttpURLConnection;
 import java.net.URL;
 import java.security.NoSuchAlgorithmException;
 import java.security.NoSuchProviderException;
@@ -70,13 +68,16 @@
   private final SecureRandom prng;
   private final URL storeUrl;
   private final String storeAPPSEC;
+  private final ContactStoreConnection.Factory connFactory;
 
   EncryptedContactStore(final URL storeUrl, final String storeAPPSEC,
-      final File pubKey, final SchemaFactory<ReviewDb> schema) {
+      final File pubKey, final SchemaFactory<ReviewDb> schema,
+      final ContactStoreConnection.Factory connFactory) {
     this.storeUrl = storeUrl;
     this.storeAPPSEC = storeAPPSEC;
     this.schema = schema;
     this.dest = selectKey(readPubRing(pubKey));
+    this.connFactory = connFactory;
 
     final String prngName = "SHA1PRNG";
     try {
@@ -157,33 +158,7 @@
       }
       u.put("account_id", String.valueOf(account.getId().get()));
       u.put("data", encStr);
-      final byte[] body = u.toString().getBytes("UTF-8");
-
-      final HttpURLConnection c = (HttpURLConnection) storeUrl.openConnection();
-      c.setRequestMethod("POST");
-      c.setRequestProperty("Content-Type",
-          "application/x-www-form-urlencoded; charset=UTF-8");
-      c.setDoOutput(true);
-      c.setFixedLengthStreamingMode(body.length);
-      final OutputStream out = c.getOutputStream();
-      out.write(body);
-      out.close();
-
-      if (c.getResponseCode() == 200) {
-        final byte[] dst = new byte[2];
-        final InputStream in = c.getInputStream();
-        try {
-          IO.readFully(in, dst, 0, 2);
-        } finally {
-          in.close();
-        }
-        if (dst[0] != 'O' || dst[1] != 'K') {
-          throw new IOException("Store failed: " + c.getResponseCode());
-        }
-      } else {
-        throw new IOException("Store failed: " + c.getResponseCode());
-      }
-
+      connFactory.open(storeUrl).store(u.toString().getBytes("UTF-8"));
     } catch (IOException e) {
       log.error("Cannot store encrypted contact information", e);
       throw new ContactInformationStoreException(e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java b/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java
new file mode 100644
index 0000000..781f401
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/contact/HttpContactStoreConnection.java
@@ -0,0 +1,74 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package com.google.gerrit.server.contact;
+
+import static com.google.inject.Scopes.SINGLETON;
+
+import com.google.gerrit.server.contact.ContactStoreConnection;
+import com.google.gerrit.server.contact.HttpContactStoreConnection;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Module;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.FactoryProvider;
+
+import org.eclipse.jgit.util.IO;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+
+/** {@link ContactStoreConnection} with an underlying {@HttpURLConnection}. */
+public class HttpContactStoreConnection implements ContactStoreConnection {
+  public static Module module() {
+    return new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(ContactStoreConnection.Factory.class)
+            .toProvider(FactoryProvider.newFactory(
+                ContactStoreConnection.Factory.class,
+                HttpContactStoreConnection.class))
+            .in(SINGLETON);
+      }
+    };
+  }
+
+  private final HttpURLConnection conn;
+
+  @Inject
+  HttpContactStoreConnection(@Assisted final URL url) throws IOException {
+    final URLConnection urlConn = url.openConnection();
+    if (!(urlConn instanceof HttpURLConnection)) {
+      throw new IllegalArgumentException("Non-HTTP URL not supported: " + urlConn);
+    }
+    conn = (HttpURLConnection) urlConn;
+  }
+
+  @Override
+  public void store(final byte[] body) throws IOException {
+    conn.setRequestMethod("POST");
+    conn.setRequestProperty("Content-Type",
+        "application/x-www-form-urlencoded; charset=UTF-8");
+    conn.setDoOutput(true);
+    conn.setFixedLengthStreamingMode(body.length);
+    final OutputStream out = conn.getOutputStream();
+    out.write(body);
+    out.close();
+    if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
+      throw new IOException("Connection failed: " + conn.getResponseCode());
+    }
+    final byte[] dst = new byte[2];
+    final InputStream in = conn.getInputStream();
+    try {
+      IO.readFully(in, dst, 0, 2);
+    } finally {
+      in.close();
+    }
+    if (dst[0] != 'O' || dst[1] != 'K') {
+      throw new IOException("Store failed: " + dst[0] + dst[1]);
+    }
+  }
+}
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 89581a1..5c3a7d9 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
@@ -25,6 +25,7 @@
 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.contact.HttpContactStoreConnection;
 import com.google.gerrit.server.git.LocalDiskRepositoryManager;
 import com.google.gerrit.server.git.PushReplication;
 import com.google.gerrit.server.git.WorkQueue;
@@ -208,6 +209,7 @@
     modules.add(sysInjector.getInstance(GitOverHttpModule.class));
     modules.add(sshInjector.getInstance(WebSshGlueModule.class));
     modules.add(CacheBasedWebSession.module());
+    modules.add(HttpContactStoreConnection.module());
     return sysInjector.createChildInjector(modules);
   }